apisec-ai-surface 1.0.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.
Files changed (54) hide show
  1. ai_surface/__init__.py +2 -0
  2. ai_surface/audits.py +110 -0
  3. ai_surface/cli.py +698 -0
  4. ai_surface/cross_promo.py +365 -0
  5. ai_surface/data/__init__.py +6 -0
  6. ai_surface/data/mcp/__init__.py +12 -0
  7. ai_surface/data/mcp/api_patterns.py +362 -0
  8. ai_surface/data/mcp/known_mcps.json +538 -0
  9. ai_surface/data/mcp/model_patterns.py +321 -0
  10. ai_surface/data/mcp/owasp_llm.py +54 -0
  11. ai_surface/data/mcp/registry.py +174 -0
  12. ai_surface/data/mcp/risk_definitions.py +185 -0
  13. ai_surface/data/mcp/secret_patterns.py +319 -0
  14. ai_surface/detectors/__init__.py +5 -0
  15. ai_surface/detectors/agent_frameworks.py +938 -0
  16. ai_surface/detectors/ai_infra.py +436 -0
  17. ai_surface/detectors/api_endpoints.py +595 -0
  18. ai_surface/detectors/env_keys.py +261 -0
  19. ai_surface/detectors/llm_sdks.py +426 -0
  20. ai_surface/detectors/mcp_audit.py +589 -0
  21. ai_surface/detectors/mcp_servers.py +420 -0
  22. ai_surface/detectors/model_gateways.py +256 -0
  23. ai_surface/detectors/vector_rag.py +235 -0
  24. ai_surface/diff.py +365 -0
  25. ai_surface/dispositions.py +64 -0
  26. ai_surface/frameworks.py +152 -0
  27. ai_surface/observability.py +224 -0
  28. ai_surface/orchestrator.py +213 -0
  29. ai_surface/oversight.py +172 -0
  30. ai_surface/pii.py +145 -0
  31. ai_surface/repo.py +118 -0
  32. ai_surface/reporters/__init__.py +1 -0
  33. ai_surface/reporters/cyclonedx_reporter.py +153 -0
  34. ai_surface/reporters/json_reporter.py +61 -0
  35. ai_surface/reporters/markdown_reporter.py +336 -0
  36. ai_surface/reporters/sarif_reporter.py +125 -0
  37. ai_surface/reporters/terminal_reporter.py +384 -0
  38. ai_surface/types.py +389 -0
  39. ai_surface/ui/README.md +118 -0
  40. ai_surface/ui/ai-bom.json +1339 -0
  41. ai_surface/ui/app.js +1581 -0
  42. ai_surface/ui/index.html +27 -0
  43. ai_surface/ui/report.json +1553 -0
  44. ai_surface/ui/styles.css +902 -0
  45. ai_surface/ui_server.py +198 -0
  46. ai_surface/utils/__init__.py +4 -0
  47. ai_surface/utils/markdown_safety.py +76 -0
  48. ai_surface/utils/specs.py +317 -0
  49. ai_surface/utils/walk.py +291 -0
  50. apisec_ai_surface-1.0.0.dist-info/METADATA +415 -0
  51. apisec_ai_surface-1.0.0.dist-info/RECORD +54 -0
  52. apisec_ai_surface-1.0.0.dist-info/WHEEL +4 -0
  53. apisec_ai_surface-1.0.0.dist-info/entry_points.txt +2 -0
  54. apisec_ai_surface-1.0.0.dist-info/licenses/LICENSE +21 -0
ai_surface/__init__.py ADDED
@@ -0,0 +1,2 @@
1
+ """ai-surface: Map the AI attack surface in your application code."""
2
+ __version__ = "1.0.0"
ai_surface/audits.py ADDED
@@ -0,0 +1,110 @@
1
+ """Deep-dive audit enrichment for validate-runtime surfaces beyond MCP.
2
+
3
+ MCP findings are audited inside the mcp_audit detector. This layer adds the
4
+ same kind of audit (severity + risk flags with OWASP + remediation) to the
5
+ OTHER validate-runtime category that would otherwise be bare: AI agents.
6
+
7
+ Posture categories (model gateways, AI infra, provider keys, LLM call sites)
8
+ are resolve-here by design and are NOT audited here: their risk_indicators
9
+ carry their substance, and inventing severity for them would be dishonest.
10
+
11
+ Run as a post-process (enrich_audits) before disposition/bridge attachment so
12
+ severity flows into the summary and the map.
13
+ """
14
+ from __future__ import annotations
15
+
16
+ from .types import (
17
+ CATEGORY_AGENT_FRAMEWORK,
18
+ SEVERITY_HIGH,
19
+ SEVERITY_LOW,
20
+ SEVERITY_MEDIUM,
21
+ SEVERITY_ORDER,
22
+ Audit,
23
+ Finding,
24
+ RiskFlag,
25
+ )
26
+
27
+ # Tool-name keyword buckets for agent risk assessment.
28
+ _FINANCIAL = ("refund", "payment", "charge", "transfer", "payout", "invoice", "wire", "ledger")
29
+ _DESTRUCTIVE = ("delete", "drop", "truncate", "purge", "remove", "revoke", "terminate")
30
+ _MESSAGING = ("send_email", "send_slack", "send_sms", "email", "slack", "sms", "notify", "message")
31
+ _READ = ("read", "get", "list", "query", "search", "fetch", "lookup")
32
+ _WRITE = ("write", "update", "create", "insert", "post", "approve", "modify")
33
+
34
+
35
+ def _hits(tools: list[str], keys: tuple[str, ...]) -> list[str]:
36
+ return [t for t in tools if any(k in t.lower() for k in keys)]
37
+
38
+
39
+ def _max_severity(flags: list[RiskFlag]) -> str | None:
40
+ if not flags:
41
+ return None
42
+ rank = {s: i for i, s in enumerate(SEVERITY_ORDER)}
43
+ return min((f.severity for f in flags), key=lambda s: rank.get(s, 99))
44
+
45
+
46
+ def agent_audit(finding: Finding) -> Audit | None:
47
+ """Compute a deep-dive audit for an agent finding from its tools + risks."""
48
+ tools = list(finding.permissions or [])
49
+ flags: list[RiskFlag] = []
50
+
51
+ fin = _hits(tools, _FINANCIAL)
52
+ dest = _hits(tools, _DESTRUCTIVE)
53
+ msg = _hits(tools, _MESSAGING)
54
+ reads = _hits(tools, _READ)
55
+
56
+ if fin:
57
+ flags.append(RiskFlag(
58
+ "financial-action", SEVERITY_HIGH,
59
+ f"Agent can invoke financial tools ({', '.join(fin)})", ["LLM06"],
60
+ "Gate financial tools behind human approval; least-privilege the agent.",
61
+ ))
62
+ if dest:
63
+ flags.append(RiskFlag(
64
+ "destructive-action", SEVERITY_HIGH,
65
+ f"Agent can invoke destructive tools ({', '.join(dest)})", ["LLM06"],
66
+ "Require confirmation and remove destructive tools from the agent's toolset.",
67
+ ))
68
+ if msg:
69
+ flags.append(RiskFlag(
70
+ "messaging-action", SEVERITY_MEDIUM,
71
+ "Agent can send outbound messages/notifications", ["LLM06"],
72
+ "Rate-limit and gate outbound messaging behind approval.",
73
+ ))
74
+ if reads and (fin or dest):
75
+ flags.append(RiskFlag(
76
+ "high-blast-radius", SEVERITY_HIGH,
77
+ "Agent combines broad read access with financial/destructive actions", ["LLM06"],
78
+ "Split read and write agents; apply least-privilege per agent.",
79
+ ))
80
+ if any("pii" in r.lower() for r in (finding.risk_indicators or [])):
81
+ flags.append(RiskFlag(
82
+ "pii-to-llm", SEVERITY_MEDIUM,
83
+ "PII flows into an LLM call from this agent", ["LLM02"],
84
+ "Redact or minimize PII before prompting; review the data flow.",
85
+ ))
86
+ if len(tools) >= 6:
87
+ flags.append(RiskFlag(
88
+ "excessive-agency", SEVERITY_LOW,
89
+ f"Agent exposes {len(tools)} tools to the model", ["LLM06"],
90
+ "Reduce the agent's toolset to the minimum required.",
91
+ ))
92
+
93
+ if not flags:
94
+ return None
95
+ owasp = sorted({o for f in flags for o in f.owasp})
96
+ return Audit(risk_flags=flags, owasp_mappings=owasp)
97
+
98
+
99
+ def enrich_audits(findings: list[Finding]) -> None:
100
+ """Add deep-dive audits (and severity) to validate-runtime findings that the
101
+ detectors left bare. In place. Skips findings already audited (e.g. MCP)."""
102
+ for f in findings:
103
+ if f.audit:
104
+ continue
105
+ audit = None
106
+ if f.category == CATEGORY_AGENT_FRAMEWORK:
107
+ audit = agent_audit(f)
108
+ if audit:
109
+ f.audit = audit
110
+ f.severity = _max_severity(audit.risk_flags)