Skip to content

feat(C-0021): cover AI/ML inference and MLOps interfaces in sensitiveInterfaces - #753

Merged
matthyx merged 1 commit into
kubescape:masterfrom
DevamShah:feat/sensitive-interfaces-ai-ml
Jul 31, 2026
Merged

matthyx merged 1 commit into
kubescape:masterfrom
DevamShah:feat/sensitive-interfaces-ai-ml

Conversation

@DevamShah

@DevamShah DevamShah commented Jun 23, 2026 •

Copy link
Copy Markdown
Contributor

Overview

Extends the sensitiveInterfaces posture-control input with the AI/ML inference and MLOps interfaces that have become standard in Kubernetes clusters — Ollama, vLLM, KServe, NVIDIA Triton, the Ray dashboard/head, MLflow, JupyterHub, Seldon and BentoML. With these names in the allowlist, the existing exposed-sensitive-interfaces-v1 rule (C-0021) immediately flags a LoadBalancer/NodePort Service that fronts any of these workloads — no rule logic changes required.

Problem / motivation

C-0021 detects sensitive interfaces exposed to the internet via LoadBalancer/NodePort Services, matching workload names against the sensitiveInterfaces list. That list predates the current wave of AI/ML serving stacks and only covers classic DevOps tooling (NiFi, Argo, Kubeflow, Weave Scope, the Kubernetes dashboard, Jenkins, Prometheus).

Modern AI/ML serving and MLOps components share the exact property that makes this control matter: they commonly ship without authentication by default and bind broadly. When exposed they enable model/prompt exfiltration and, in several cases, remote code execution on cluster nodes:

  • Ray — the dashboard's Jobs API allows arbitrary job submission with no auth; abused in the wild for cryptojacking ("ShadowRay", CVE-2023-48022, disputed by the vendor but actively exploited).
  • vLLM / Ollama / Triton / KServe / Seldon / BentoML — OpenAI-compatible or gRPC/HTTP inference endpoints with no built-in authN/Z; exposure leaks served models and prompts and provides an unauthenticated inference surface.
  • MLflow — tracking server has a documented LFI/RFI and path-traversal history (e.g. CVE-2023-6014, CVE-2023-6018) reachable when the UI/API is exposed.
  • JupyterHub — exposed notebooks provide interactive code execution inside the cluster.

This is the same class of "exposed sensitive interface" the control already guards (MITRE ATT&CK for Containers, Initial Access — Exposed Sensitive Interfaces) and is reflected in OWASP's ML/LLM security guidance. The gap is a coverage false-negative: real, high-impact exposures go unflagged today.

Change

  • default-config-inputs.json — appended ten entries to settings.postureControlInputs.sensitiveInterfaces: ollama, vllm, kserve, triton-inference-server, ray-dashboard, ray-head, mlflow, jupyterhub, seldon, bentoml.
  • controls/C-0021-exposedsensitiveinterfaces.json — updated description and long_description to note that the same exposure pattern applies to AI/ML inference and MLOps interfaces, with examples.
  • rules/exposed-sensitive-interfaces-v1/test/vllm/ — new test case: an exposed vLLM Deployment + LoadBalancer Service, with the expected alert, mirroring the existing workloads (LoadBalancer) and workloads2 (NodePort) fixtures exactly.

kubeflow-pipelines is intentionally not added: the rule uses a substring match (contains(wl.metadata.name, wl_name)), so the existing kubeflow entry already covers kubeflow-pipelines* workload names. The names chosen above are specific enough to avoid broad substring collisions (e.g. ray-dashboard/ray-head rather than ray, triton-inference-server rather than triton).

Security rationale

  • Framework / mapping: MITRE ATT&CK for Containers — Initial Access, Exposed Sensitive Interfaces (the control's existing microsoftMitreColumns tag). The added interfaces are direct, current instances of that technique.
  • OWASP: aligns with OWASP LLM/ML security guidance on exposed inference and MLOps endpoints (model/prompt disclosure, unauthenticated inference, supply-chain/RCE via model servers).
  • Representative CVEs/exposure classes: Ray dashboard unauthenticated job submission (CVE-2023-48022, "ShadowRay" in-the-wild cryptojacking); MLflow path traversal / file read (CVE-2023-6014, CVE-2023-6018). These are reachable precisely when the interface is fronted by a LoadBalancer/NodePort Service — exactly what C-0021 detects.
  • Impact framing: for a security team, an internet-exposed model server is both a data-exposure (models, prompts, potentially PII in prompts) and an RCE/lateral-movement risk into the cluster. Surfacing it in an existing, already-trusted control is high-signal and low-cost.

Testing / validation

Run from testrunner/ (go1.26.2, -tags=static):

# Targeted — the touched rule (includes the new vllm case)
go test -tags="static" rego_test.go -run TestSingleRule -args -rule exposed-sensitive-interfaces-v1
# PASS — pod, workloads, workloads2, vllm

# Full suite — confirms the shared config edit causes no regressions
go test -tags="static" rego_test.go -run TestAllRules
# ok  (337s)
  • New positive case (vllm): an exposed vLLM Deployment behind a LoadBalancer Service is correctly flagged.
  • False-positive control: the rule still requires a LoadBalancer/NodePort Service selector-matched to the workload, so ClusterIP-only AI workloads (the common, non-exposed case) are not flagged — the entire existing test matrix continues to pass unchanged.
  • All touched JSON validated as well-formed; the control file's existing ’ (’) escaping convention is preserved.

Checklist before requesting a review

  • My code follows the style guidelines of this project
  • I have performed a self-review of my code
  • If it is a core feature, I have added thorough tests.
  • New and existing unit tests pass locally with my changes

Summary by CodeRabbit

  • New Features

    • Enhanced detection of exposed sensitive interfaces to include AI/ML frameworks: vLLM, Ollama, KServe, Triton Inference Server, Ray, MLflow, JupyterHub, Seldon, and BentoML.
    • Added Prometheus monitoring interface detection.
  • Documentation

    • Expanded control descriptions with detailed examples of sensitive interfaces and frameworks.

Extend the sensitiveInterfaces posture-control input with AI/ML inference
and MLOps workloads that commonly ship without authentication by default:
ollama, vllm, kserve, triton-inference-server, ray-dashboard, ray-head,
mlflow, jupyterhub, seldon and bentoml.

With these names in the allowlist, the existing exposed-sensitive-
interfaces-v1 rule (C-0021) flags a LoadBalancer/NodePort Service that
fronts any of these workloads, with no rule logic change. Update the
C-0021 control description and long_description to document the AI/ML
exposure pattern, and add a vllm test fixture (exposed Deployment +
LoadBalancer Service) mirroring the existing workloads/workloads2 cases.

kubeflow-pipelines is intentionally omitted: the rule uses a substring
match, so the existing kubeflow entry already covers it.

Signed-off-by: Devam Shah <devamshah91@gmail.com>
@coderabbitai

coderabbitai Bot commented Jun 23, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: bb6e432b-3b45-45b7-9583-af28e0098584

📥 Commits

Reviewing files that changed from the base of the PR and between c864aea and e02d33a.

📒 Files selected for processing (5)
  • controls/C-0021-exposedsensitiveinterfaces.json
  • default-config-inputs.json
  • rules/exposed-sensitive-interfaces-v1/test/vllm/expected.json
  • rules/exposed-sensitive-interfaces-v1/test/vllm/input/deployment.yaml
  • rules/exposed-sensitive-interfaces-v1/test/vllm/input/service.yaml

📝 Walkthrough

Walkthrough

Control C-0021 (exposed sensitive interfaces) is updated to explicitly cover AI/ML inference and MLOps frameworks. The control's description and long description are expanded, the sensitiveInterfaces list in default-config-inputs.json gains ten new identifiers, and a new vLLM test fixture (Deployment, Service, and expected alert) is added.

Changes

AI/ML Sensitive Interface Coverage

Layer / File(s) Summary
Control description and config list expansion
controls/C-0021-exposedsensitiveinterfaces.json, default-config-inputs.json
C-0021 description and long_description are rewritten to list AI/ML/MLOps frameworks; sensitiveInterfaces in the default config is extended with ollama, vllm, kserve, triton-inference-server, ray-dashboard, ray-head, mlflow, jupyterhub, seldon, and bentoml.
vLLM test fixtures and expected alert
rules/exposed-sensitive-interfaces-v1/test/vllm/...
New input/deployment.yaml and input/service.yaml define a vLLM workload exposed via a LoadBalancer Service; expected.json asserts one alert with alertScore: 7 for vllm-service in the ml-serving namespace.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~5 minutes

Poem

🐇 Hop hop, the rabbit adds new names,
Triton, vLLM, and MLflow frames,
No exposed port shall go unseen,
From Ray to Seldon, BentoML too—
The warren is secured and clean! 🌟

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main change: expanding C-0021 to cover AI/ML inference and MLOps interfaces by adding them to sensitiveInterfaces.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@matthyx matthyx moved this to Needs Reviewer in KS PRs tracking Jul 3, 2026
@matthyx
matthyx requested a review from slashben July 3, 2026 05:25

@matthyx matthyx 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.

Reviewed the change end-to-end — no blockers. Summary plus two notes below.

Sound and merge-safe

  • Purely additive to settings.postureControlInputs.sensitiveInterfaces; exposed-sensitive-interfaces-v1 needs no logic change, as the description states.
  • The new test/vllm/ fixture mirrors the existing workloads LoadBalancer case exactly: Deployment spec.selector.matchLabels equals the Service spec.selector (app: vllm), Service is LoadBalancer with status.loadBalancer.ingress[0].ip set, and expected.json matches the rule's wlvector output shape (name/namespace/kind/relatedObjects). It should pass alongside pod/workloads/workloads2, and the Deployment name matches only the single vllm entry, so exactly one alert is produced.
  • Touched JSON is well-formed and there is no duplicate sensitiveInterfaces list elsewhere in the repo to keep in sync (default-config-inputs.json is the single source; releaseDev is generated in CI).
  • Good calls keeping entries specific (ray-dashboard/ray-head, triton-inference-server) to avoid broad substring collisions, and skipping kubeflow-pipelines since kubeflow already covers it via the substring match.

One gate before merge (not a code issue)

  • The pr-tests workflow — which runs the Go rego suite, regal lint, and export.py — has not run on this PR; its status is action_required. Only DCO / GitGuardian / CodeRabbit have run. Because this is a fork PR, a maintainer needs to approve the workflow run, so the suite the description reports as green locally has not yet been validated in CI. Worth approving/running before merge.

Non-blocking coverage note

  • The rule matches on workload name substrings (contains(wl.metadata.name, wl_name)). ollama, vllm, mlflow, jupyterhub, and KubeRay head pods (*-head → contains ray-head) typically carry these names, so they'll match. However, KServe (<isvc>-predictor-…), Seldon (<sdep>-<predictor>-…), and Triton deployed under KServe/Seldon usually get model-derived workload names that don't contain kserve / seldon / triton-inference-server, so those three entries may match fewer real-world deployments than expected. Not a reason to hold the PR — just a candidate for a follow-up (e.g. label/annotation-based matching) if coverage on those stacks matters.

@matthyx matthyx closed this Jul 31, 2026
@matthyx matthyx reopened this Jul 31, 2026
@matthyx
matthyx merged commit f1e4614 into kubescape:master Jul 31, 2026
25 of 28 checks passed
@matthyx matthyx moved this from Needs Reviewer to To Archive in KS PRs tracking Jul 31, 2026
@DevamShah

Copy link
Copy Markdown
Contributor Author

Sorry for the long silence on your second note. Picking it back up now.

You were right, and it's still true on master. The rule is unchanged (contains(wl.metadata.name, wl_name)), so I checked the entries against realistic workload names: sklearn-iris-predictor, iris-model-predictor-default and mymodel-default-classifier all miss the kserve / seldon / triton-inference-server entries, exactly as you described. ray-head turns out to have the same shape of problem. It catches the default raycluster-kuberay-head-xxxxx, but a cluster named my-cluster gives my-cluster-head-xxxxx, which doesn't match.

One correction to something we both assumed in that thread: kubeflow doesn't cover Kubeflow Pipelines. The upstream Deployment in manifests/kustomize/base/pipeline is named ml-pipeline-ui, with no kubeflow substring anywhere in the name, so the KFP UI is unmatched today.

Going through the obvious siblings against the list on master, these are genuinely missing: TorchServe (the pytorch/serve chart names the Deployment torchserve), the KFP UI (ml-pipeline-ui), Label Studio, and Weights & Biases local. Plain Jupyter is a partial gap too, since jupyterhub doesn't match jupyter-notebook or jupyterlab.

I've got those four entries plus jupyterhub widened to jupyter on a branch, with test/torchserve and test/kfp-ui fixtures in the same shape as the vllm one. Config and fixtures only, no rule change, and the rego suite is green locally. Happy to open it if you want it, just say the word.

The label-based matching you suggested is the better fix for KServe and Seldon, since those names are model-derived and no name list will catch them. That needs a new config input (something like sensitiveInterfaceLabels) and another deny block matching on serving.kserve.io/inferenceservice, seldon-deployment-id and ray.io/node-type: head. It touches the rule rather than just config, so I'd rather you shape it than have me guess. Let me know if you want that in the same PR or kept separate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

2 participants