Skip to content

ai-assistant: docs/holmes: Add Holmes STRIDE threat model#885

Open
illume wants to merge 1 commit into
headlamp-k8s:mainfrom
illume:docs/ai-assistant-holmes-threat-model
Open

ai-assistant: docs/holmes: Add Holmes STRIDE threat model#885
illume wants to merge 1 commit into
headlamp-k8s:mainfrom
illume:docs/ai-assistant-holmes-threat-model

Conversation

@illume

@illume illume commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Adds docs/holmes/holmes-stride-threat-model.md — a STRIDE threat model for the Holmes integration, including network-level and data-integrity risks with mitigations.

Assisted by Copilot.

Part of the ai-assistant Holmes documentation series.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a STRIDE threat model document for the AI Assistant’s Holmes (HolmesGPT) integration to capture key security risks, trust boundaries, and mitigations for the proxy-chain + in-cluster agent architecture.

Changes:

  • Introduces a new Holmes STRIDE threat model doc with system overview (components, data flow, trust boundaries).
  • Documents STRIDE threats across spoofing/tampering/repudiation/info-disclosure/DoS/EoP with risks and mitigations.
  • Provides a prioritized recommended-actions list for hardening and documentation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +11 to +14
| **HolmesAgent** | `ai-common/src/agent/holmesClient.ts` | AG-UI client wrapper — manages threads, messages, SSE event subscriptions |
| **getHolmesServiceProxyPath()** | `ai-common/src/agent/holmesClient.ts` | Builds K8s service proxy path for routing requests to Holmes |
| **getHolmesProxyBaseUrl()** | `ai-common/src/agent/holmesClient.ts` | Builds full absolute URL including backend origin and cluster routing |
| **checkHolmesAgentHealth()** | `ai-common/src/agent/holmesClient.ts` | Health probe via K8s service proxy |
Comment on lines +15 to +17
| **ClusterRequestFn** | `ai-common/src/agent/holmesClient.ts` | Injectable interface for platform-specific cluster requests |
| **HolmesPluginConfig** | `ai-common/src/agent/holmesClient.ts` | Configuration: namespace, service name, port |
| **holmesClient wrapper** | `ai-assistant/src/holmesClient.ts` | Pre-binds headlamp-plugin's `clusterRequest` to `ClusterRequestFn` |
| **Risk** | **Low** — requires control over the browser environment or an XSS vulnerability. |
| **Fix** | Validate the origin against an allowlist. Avoid relying on mutable `window` properties for security-critical decisions. |

#### S3: ClusterRequestFn Injection
Comment on lines +98 to +101
| **Threat** | The `ClusterRequestFn` interface is injected at runtime. A compromised plugin or module could inject a malicious request function that redirects cluster requests, logs credentials, or modifies responses. |
| **Mitigation** | The injection point is controlled by the host application code (`ai-assistant/src/holmesClient.ts`). |
| **Risk** | **Low** — requires code-level compromise of the host application. |
| **Fix** | Freeze the injected function reference. Type-check at injection time. |
| | |
|---|---|
| **Threat** | If the Holmes pod is down, overloaded, or evicted, the AI Assistant loses diagnostic capability. The health check returns `false` but the user experience degrades silently. |
| **Mitigation** | `checkHolmesAgentHealth()` has a 5-second timeout. The AI Assistant falls back to its own LLM without Holmes when the agent is unavailable. |
| | |
|---|---|
| **Threat** | An attacker with namespace-level access could deploy a Service with the same name (`holmesgpt-holmes`) that impersonates the real Holmes agent. The AI Assistant would connect to the malicious service and receive fabricated diagnostic responses. |
| **Mitigation** | The service name and namespace are configurable via `HolmesPluginConfig`. The K8s API server authenticates the proxy request. However, there is no mutual authentication — the AI Assistant trusts whatever responds at the configured service path. |

| | |
|---|---|
| **Threat** | `HolmesPluginConfig` values (namespace, service name, port) are stored in the plugin store. Tampering with these values could redirect Holmes requests to a malicious service. |

| | |
|---|---|
| **Threat** | `HolmesPluginConfig` allows configuring any namespace, service name, and port (1–65535). A malicious config could redirect the proxy to an unrelated service (e.g., a database, internal API) and use the Holmes client as an SSRF vector. |
| **E3** | EoP | Prompt injection via Holmes response | **Medium** | ⚠️ Partial (approval flow for tool calls) |
| **E4** | EoP | Port config targets other services | **Medium** | ⚠️ Partial (port validation only) |
| **S2** | Spoofing | Backend origin spoofing | **Low** | ⚠️ Partial (production uses same origin) |
| **S3** | Spoofing | ClusterRequestFn injection | **Low** | ⚠️ Partial (controlled injection point) |
| **R2** | Repudiation | Health check results not logged | **Low** | ❌ Not mitigated |
| **I3** | Info Disclosure | Service proxy path reveals topology | **Low** | ✅ Acceptable (standard K8s) |
| **I4** | Info Disclosure | Console logging of Holmes URL | **Low** | ❌ Not mitigated |
| **D1** | DoS | Holmes agent unavailability | **Low** | ✅ Mitigated (graceful fallback) |
@illume illume force-pushed the docs/ai-assistant-holmes-threat-model branch 2 times, most recently from e0e5abe to 413b081 Compare July 8, 2026 11:52
@illume illume requested a review from Copilot July 8, 2026 11:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 6 comments.

Comment on lines +11 to +18
| **HolmesAgent** | `ai-common/src/agent/holmesClient.ts` | AG-UI client wrapper — manages threads, messages, SSE event subscriptions |
| **getHolmesServiceProxyPath()** | `ai-common/src/agent/holmesClient.ts` | Builds K8s service proxy path for routing requests to Holmes |
| **getHolmesProxyBaseUrl()** | `ai-common/src/agent/holmesClient.ts` | Builds full absolute URL including backend origin and cluster routing |
| **checkHolmesAgentHealth()** | `ai-common/src/agent/holmesClient.ts` | Health probe via K8s service proxy |
| **ClusterRequestFn** | `ai-common/src/agent/holmesClient.ts` | Injectable interface for platform-specific cluster requests |
| **HolmesPluginConfig** | `ai-common/src/agent/holmesClient.ts` | Configuration: namespace, service name, port |
| **holmesClient wrapper** | `ai-assistant/src/holmesClient.ts` | Pre-binds headlamp-plugin's `clusterRequest` to `ClusterRequestFn` |
| **Holmes Pod** | In-cluster | HolmesGPT AG-UI server (`server-agui.py`) deployed via Helm chart |
Comment on lines +94 to +101
#### S3: ClusterRequestFn Injection

| | |
|---|---|
| **Threat** | The `ClusterRequestFn` interface is injected at runtime. A compromised plugin or module could inject a malicious request function that redirects cluster requests, logs credentials, or modifies responses. |
| **Mitigation** | The injection point is controlled by the host application code (`ai-assistant/src/holmesClient.ts`). |
| **Risk** | **Low** — requires code-level compromise of the host application. |
| **Fix** | Freeze the injected function reference. Type-check at injection time. |
| | |
|---|---|
| **Threat** | An attacker with namespace-level access could deploy a Service with the same name (`holmesgpt-holmes`) that impersonates the real Holmes agent. The AI Assistant would connect to the malicious service and receive fabricated diagnostic responses. |
| **Mitigation** | The service name and namespace are configurable via `HolmesPluginConfig`. The K8s API server authenticates the proxy request. However, there is no mutual authentication — the AI Assistant trusts whatever responds at the configured service path. |

| | |
|---|---|
| **Threat** | `HolmesPluginConfig` values (namespace, service name, port) are stored in the plugin store. Tampering with these values could redirect Holmes requests to a malicious service. |
| | |
|---|---|
| **Threat** | If the Holmes pod is down, overloaded, or evicted, the AI Assistant loses diagnostic capability. The health check returns `false` but the user experience degrades silently. |
| **Mitigation** | `checkHolmesAgentHealth()` has a 5-second timeout. The AI Assistant falls back to its own LLM without Holmes when the agent is unavailable. |

| | |
|---|---|
| **Threat** | `HolmesPluginConfig` allows configuring any namespace, service name, and port (1–65535). A malicious config could redirect the proxy to an unrelated service (e.g., a database, internal API) and use the Holmes client as an SSRF vector. |
STRIDE threat model for the Holmes integration.

Covers threats specific to routing requests through the Kubernetes API server
proxy to an in-cluster agent:

- Spoofing: SSRF via a crafted `holmesServiceUrl`; mitigated by restricting
  the URL to the K8s service proxy path format.
- Tampering: injected or replayed SSE events from a compromised Holmes agent;
  mitigated by event-type validation and thread isolation.
- Information disclosure: cluster topology or secret names surfaced in Holmes
  diagnostics; mitigated by operating within the user's existing K8s RBAC scope.
- Denial of service: slow or infinite SSE streams; mitigated by per-request
  timeouts and stream abort on component unmount.
- Elevation of privilege: Holmes agent acting beyond its intended K8s RBAC role;
  mitigated by deploying Holmes with minimal permissions.

Signed-off-by: René Dudfield <renedudfield@microsoft.com>
Co-authored-by: Ashu Ghildiyal <aghildiyal@microsoft.com>
Signed-off-by: Ashu Ghildiyal <aghildiyal@microsoft.com>
@illume illume force-pushed the docs/ai-assistant-holmes-threat-model branch from 413b081 to 8338fe8 Compare July 8, 2026 11:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants