This is an automated email from the ASF dual-hosted git repository.

oscerd pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-karavan.git


The following commit(s) were added to refs/heads/main by this push:
     new 02643138 chore: add draft threat model (#1642)
02643138 is described below

commit 026431385763e61a04abe168c51e62b16a34bf8c
Author: Andrea Cosentino <[email protected]>
AuthorDate: Tue Sep 8 14:32:10 2026 +0200

    chore: add draft threat model (#1642)
    
    * chore: add draft threat model
    
    Adds docs/threat-model.md, a first draft of Karavan's threat model
    following the ASF Security threat-model-producer rubric.
    
    Karavan has no SECURITY.md and no entry in the ASF security site's
    project-coordinates.json. The Apache Camel security model
    (camel.apache.org/manual/security-model.html) scopes itself to
    apache/camel artifacts and notes that sibling subprojects have their
    own security surfaces, so Karavan currently has no document a triager
    can cite when classifying a vulnerability report or a scanner finding.
    
    The draft is written from public artifacts only. Every claim carries a
    (documented) / (maintainer) / (inferred) provenance tag: 53 documented,
    0 maintainer, 28 inferred. The inferred claims are unratified
    hypotheses, each routed to a numbered question in section 4.14 for the
    maintainers to confirm, correct, or strike.
    
    Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
    
    * chore: fold maintainer answers into the threat model
    
    @mgubaidullin answered waves 1-3 on #1642. Every hypothesis in the first
    draft is now confirmed, corrected, or superseded: 57 documented /
    40 maintainer / 0 inferred, down from 28 inferred.
    
    Rulings that changed the model rather than confirming it:
    
    - Q11 corrected the draft. The non-invalidating
      /platform/internal/sources/{projectId}/{filename} route is by design,
      not an oversight; the single-use guarantee is scoped to the
      whole-project route only.
    - Q5 confirmed the negative side-effect inventory is accurate but
      declined to commit to it as an invariant, so it is recorded as a
      description of the current release rather than a promise.
    - Q1 ruled the default platform.password an install-time convenience
      set via secret or env var and changed through the UI, making reports
      against it OUT-OF-MODEL: non-default-build.
    
    Q9 was answered "already fixed", which rebinds the document. CsrfFilter
    (d211d71f), PathUtils name validation (5e425249) and the Kubernetes
    resource allow-list all landed after the 4.22.0 tag, so the model now
    binds to main at 677a293a and says explicitly that a report against
    4.22.0 or earlier is triaged against a model without those three. CSRF
    moved from a section 4.9 false friend to a claimed property in 4.8.
    
    The Kubernetes resource validation is described as defence in depth and
    explicitly not a boundary: it does not cover the builder pod path,
    build.sh, or the Docker compose path.
    
    Q13 and Q14, on document ownership and revision policy, remain open.
    Appendix B records every ruling so a disputed disposition can be traced
    to the answer behind it.
    
    Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
    
    ---------
    
    Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
---
 docs/threat-model.md | 825 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 825 insertions(+)

diff --git a/docs/threat-model.md b/docs/threat-model.md
new file mode 100644
index 00000000..f38a0fd2
--- /dev/null
+++ b/docs/threat-model.md
@@ -0,0 +1,825 @@
+# Apache Camel Karavan — Threat Model
+
+| | |
+| --- | --- |
+| **Project** | Apache Camel Karavan |
+| **Version / commit** | 4.22.0 plus post-release hardening on `main` — 
`677a293a` |
+| **Date** | 2026-09-08 |
+| **Status** | **Maintainer-reviewed.** Waves 1–3 answered by @mgubaidullin on 
2026-09-01 (apache/camel-karavan#1642). Two questions on document ownership 
remain open (§4.14). |
+| **Author** | Drafted with the ASF Security `threat-model-producer` rubric; 
ratified by the Karavan maintainers. |
+
+## Version binding
+
+This model is versioned alongside the project and should be tagged with 
releases. A
+report filed against Karavan version *N* is triaged against the model as it 
stood at
+*N*, not against HEAD.
+
+**This revision is bound to `main` after 4.22.0, not to the 4.22.0 release 
itself.**
+Three controls described here — CSRF validation (§4.8 property 13), 
project-file name
+validation (property 14), and Kubernetes resource validation (§4.5a, §4.9) — 
landed in
+`d211d71f` and `5e425249` *after* the 4.22.0 tag. A report filed against 
4.22.0 or
+earlier is triaged against a model in which those three do not exist.
+
+## Reporting cross-reference
+
+Findings that violate a property claimed in §4.8 should be reported privately 
to
+`[email protected]` per the ASF disclosure process — **not** as a GitHub 
issue.
+Findings that land in §4.3 (out of scope), §4.9 (disclaimed properties), or 
§4.11a
+(known non-findings) will be closed citing this document.
+
+## Provenance legend
+
+Every non-trivial claim carries one of three tags:
+
+| Tag | Meaning |
+| --- | --- |
+| *(documented)* | Stated in the project's own artifacts — source, config, 
install docs, or the Apache Camel security model. Cited. |
+| *(maintainer)* | Stated by a Karavan maintainer in response to this process. 
Dated. |
+| *(inferred)* | Reasoned from code structure or the absence of a feature. Not 
yet confirmed; has a matching question in §4.14. |
+
+## Confidence
+
+**57 documented / 40 maintainer / 0 inferred.** Every hypothesis in the first 
draft has
+been confirmed, corrected, or superseded by a maintainer answer; nothing in 
the body is
+unratified. The two questions still open in §4.14 concern who owns this 
document and how
+it is revised — neither affects a claim made here.
+
+## What Karavan is
+
+Apache Camel Karavan is a low-code data-integration platform. It gives a team 
a web
+UI (and a companion VS Code extension) for visually designing Apache Camel 
routes,
+storing them in a Git repository that acts as the source of truth, running them
+locally in "developer mode" containers, building them into container images, 
and
+deploying them to Docker or Kubernetes/OpenShift. The server component is a 
Quarkus
+application that holds credentials for a Git repository and an image registry, 
and
+that drives either the host Docker daemon or the Kubernetes API on the user's 
behalf.
+*(documented — `README.md`, `docs/install/`)*
+
+---
+
+## 4.2 Scope and intended use
+
+Karavan is designed to be run by a team as **an internal developer platform on 
a
+trusted network** — the same posture as a CI server or an internal PaaS 
console.
+*(maintainer, 2026-09 — §4.14 Q1)* It is not a multi-tenant SaaS product, and 
it is not an
+appliance intended to face the public internet.
+
+### Caller roles
+
+Karavan is a service, not a library, so "the caller" splits into four roles. 
These map
+onto the vocabulary already established by the Apache Camel security model
+*(documented — <https://camel.apache.org/manual/security-model.html>)*:
+
+| Role | Trust | Notes |
+| --- | --- | --- |
+| **Operator / deployer** | Fully trusted | Installs Karavan, sets 
`platform.auth`, supplies Git and registry credentials, mounts `docker.sock` or 
binds the Kubernetes `Role`. Equivalent to the Camel model's "deployment 
operator". |
+| **Authenticated Karavan user** | **Fully trusted** | Any account with any of 
`platform-user` / `platform-developer` / `platform-admin`. Equivalent to the 
Camel model's "route author", which that model declares fully trusted and able 
to execute arbitrary code by design. |
+| **Service-account token holder** | **Fully trusted** | A 
`platform-service-account` identity created from `/ui/access/tokens`. 
Functionally equivalent to an authenticated user for everything except the 
`/ui/access` administration surface. *(maintainer, 2026-09 — §4.14 Q4)* |
+| **Unauthenticated network peer** | **Untrusted — the primary adversary** | 
Anyone who can reach the Karavan HTTP port but holds no valid session or token. 
|
+
+The critical consequence: **the trust boundary is authentication, and nothing 
after
+it.** A user who can log in can, by design, cause arbitrary code to run on the 
Docker
+host or in the Kubernetes namespace. This is the intended function of the 
product, not
+a defect.
+
+### Component families
+
+| Family | Entry point | Touches outside the process? | In this model? |
+| --- | --- | --- | --- |
+| **Karavan server API** | `karavan-app` — JAX-RS resources under `/ui/*`, 
`/platform/internal/*`, `/public/*` | Yes: Docker socket, Kubernetes API, Git 
remote, image registry, PostgreSQL | **In scope — this is the core** |
+| **Karavan web UI** | `karavan-app/src/main/webui` React SPA, served 
same-origin | Browser only | **In scope** |
+| **DevMode / builder image** | `karavan-devmode` — `entrypoint.sh`, 
`KaravanDevMode` | Yes: clones Git, runs Maven/JiB, pushes images, runs the 
user's Camel routes | **In scope as an executor**, but see §4.3 — the routes it 
runs are governed by the Camel security model, not this one |
+| **VS Code extension** | `karavan-vscode` | Local filesystem, local 
JBang/Maven/`kubectl`/`oc` via terminal | **In scope, separately** — see §4.2.1 
|
+| **Code generator** | `karavan-generator` | Build-time only; not shipped at 
runtime | Out of scope — §4.3 |
+| **Reference install manifests** | `docs/install/karavan-docker`, 
`karavan-kubernetes`, `karavan-helm` | n/a | **In scope as documented 
posture**, out of scope as production-ready config — §4.3 |
+| **Repo dev tooling** | `Dockerfile.claude`, `claude_*.sh`, `release-utils/` 
| n/a | Out of scope — §4.3 |
+
+### 4.2.1 The VS Code extension is a different product
+
+`karavan-vscode` has an entirely different threat profile from the server: it 
runs
+wholly on a developer's own machine, exposes no network listener, and its 
"caller" is
+the developer who installed it. *(documented — `docs/VSCODE_INSTALL.md`, 
`README.md`)*
+It shells out to JBang, Maven, `kubectl` and `oc` through VS Code terminals
+*(documented — `karavan-vscode/src/exec.ts`, `jbang.ts`, `maven.ts`)*, which 
is its
+purpose. The relevant adversary for it is a **malicious workspace**: a 
repository the
+developer opens that contains crafted Camel YAML or `application.properties`. 
Whether
+opening an untrusted workspace in the extension is a supported scenario is an 
open
+question — see §4.14 Q10.
+
+---
+
+## 4.3 Out of scope (explicit non-goals)
+
+**Uses Karavan does not aim to support:**
+
+- **Multi-tenancy.** Karavan is not a tenancy boundary. All projects live in 
one Git
+  repository, one database, and one Docker network or Kubernetes namespace. 
*(maintainer, 2026-09
+  — §4.14 Q2)*
+- **Internet-facing deployment.** Nothing in the reference deployment 
terminates TLS,
+  rate-limits, or fronts the API with a WAF. *(documented — 
`docs/install/karavan-helm/values.yaml`
+  ships `ingress.tls: false`; `docs/WEB_DOCKER.md` publishes port 8080 
directly.)*
+- **Being a security boundary between its own users.** See §4.9.
+
+**Threats deliberately not defended against:**
+
+- **A Karavan user escalating to host or namespace privileges.** This is the 
product's
+  function. Karavan is given the Docker socket *(documented —
+  `docs/install/karavan-docker/docker-compose.yaml`: 
`"/var/run/docker.sock:/var/run/docker.sock"`,
+  with the comment "Allows Karavan to build and manage Docker containers on 
the host")*
+  or a Kubernetes `Role` with `["*"]` on `secrets`, `configmaps`, 
`serviceaccounts`,
+  `pods`, `services`, `deployments`, `ingresses`, PVs/PVCs plus `create` on 
`pods/exec`
+  *(documented — `docs/install/karavan-kubernetes/role.yaml`)*. A logged-in 
user
+  driving that is working as designed.
+- **Anything inside a running Camel route.** Once an integration is deployed, 
its
+  security is governed by the Apache Camel security model, which is a separate 
document
+  with its own scope. *(documented — the Camel security model states it covers
+  `apache/camel` artifacts and that sibling subprojects "have their own 
security
+  surfaces".)* A header-injection or deserialization issue in a Camel 
component is a
+  Camel report, not a Karavan report.
+- **Compromise of the Git repository or image registry.** Both are trusted 
inputs; see
+  §4.6. *(maintainer, 2026-09 — §4.14 Q3)*
+- **Denial of service through resource exhaustion.** Consistent with the Camel 
model,
+  which places DoS out of scope. Karavan places no quota on how many devmode 
or build
+  containers a user may start. *(maintainer, 2026-09 — §4.14 Q7)*
+- **Transitive third-party CVEs**, absent a demonstrated path from an in-scope 
adversary
+  to a Karavan-claimed property. *(maintainer, 2026-09 — §4.14 Q3)*
+
+**Code that ships but is not covered:**
+
+- `karavan-generator/` — a build-time code generator that reads the Camel 
catalog and
+  emits TypeScript/Java model classes. It never runs in a deployed Karavan. 
Threat-model
+  separately if it ever ingests untrusted catalogs.
+- `release-utils/`, `change_version.sh`, `claude_*.sh`, `Dockerfile.claude` — 
maintainer
+  tooling, not shipped to users.
+- `docs/install/*` — **reference manifests, not a hardened production 
configuration.**
+  They contain placeholder credentials and TLS-off defaults by design (see 
§4.11a).
+  Findings against them are `OUT-OF-MODEL: unsupported-component` unless the 
finding is
+  that the documentation fails to *say* they need hardening — which is a §4.10 
doc gap.
+
+---
+
+## 4.4 Trust boundaries and data flow
+
+There is exactly **one security boundary in Karavan: HTTP authentication at the
+`karavan-app` API surface.** Everything else in the diagram is inside that 
boundary.
+
+```
+  UNTRUSTED                    │  TRUSTED (route-author equivalent)
+                               │
+  browser / HTTP client ──────►│ karavan-app  ──► PostgreSQL (state, users, 
sessions)
+   • no session, no token      │   /ui/*        ──► Git remote      (source of 
truth)
+   • ← THE ADVERSARY           │   /platform/*  ──► Image registry
+                               │   /public/*    ──► Docker socket  ── root on 
host
+                               │                └─► Kubernetes API ── 
namespace admin
+                               │                        │
+                               │                        ▼
+                               │                 devmode / builder container
+                               │                  • runs user's Camel routes
+                               │                  • runs configuration/build.sh
+                               │                        │
+  ─────────────────────────────┼────────────────────────┼─────────────────────
+  Integration message traffic  │  governed by the Apache Camel security model
+```
+
+### Trust transitions
+
+| Transition | What crosses | Trust change |
+| --- | --- | --- |
+| HTTP request → `CookieSessionAuthMechanism` / `TokenAuthenticationMechanism` 
| `sessionId` cookie, `Authorization: Bearer`, `X-API-Key` | **untrusted → 
fully trusted.** The only transition that matters. *(documented — 
`karavan-app/.../api/CookieSessionAuthMechanism.java`, 
`TokenAuthenticationMechanism.java`)* |
+| Project file write → Git commit → devmode/build | Camel YAML, 
`application.properties`, `docker-compose.yaml`, `configuration/build.sh` | No 
change — trusted throughout. Project files are **code**, authored by trusted 
users. |
+| `karavan-app` → Docker daemon | container spec derived from the project's 
compose file, including image, bind mounts, ports and `/bin/sh -c` command 
*(documented — `DockerService.createContainer`)* | No change — Karavan is fully 
privileged on the daemon. |
+| `karavan-app` → Kubernetes API | pod/deployment manifests derived from 
`configuration/builder.pod.jkube.yaml` | No change — Karavan holds its 
namespace `Role`. |
+| Builder container → `/platform/internal/sources/{projectId}` | one-shot 
`sessionId` env var, invalidated after use *(documented — 
`InternalResource.getProjectFiles` invalidates in `finally`)* | Re-entry into 
the trusted zone with a short-lived credential. |
+| devmode container → integration peers | Camel exchange data | **Karavan's 
model ends here.** Camel's model begins. |
+
+### Reachability preconditions per component
+
+Apply these before anything else when triaging a tool or AI finding:
+
+- A finding in `org.apache.camel.karavan.api.*` is in model **only if** it is 
reachable
+  by a caller holding no valid session and no valid API token, i.e. from
+  `@PermitAll`-annotated endpoints (`/ui/auth/type`, `/ui/auth/sso-config`,
+  `/ui/auth/login`, `/ui/auth/logout`, `/public/readiness`,
+  `/platform/internal/sources/**`), the static SPA assets, or the 
authentication
+  mechanisms themselves. A finding reachable only after `@Authenticated` 
succeeds is
+  `OUT-OF-MODEL: adversary-not-in-scope`.
+- A finding in `org.apache.camel.karavan.docker.*` or `.kubernetes.*` is in 
model **only
+  if** the attacker-controlled value reaches it without passing through an 
authenticated
+  request or a project file. In practice this is almost never true; container 
specs are
+  route-author input.
+- A finding in `CodeService`, `ProjectService`, or `GitService` is in model 
**only if**
+  triggered by data Karavan did not receive from a trusted user or from the Git
+  repository.
+- A finding in `karavan-devmode` is in model **only if** it lets *untrusted 
integration
+  traffic* — not the route author — affect the container. Everything the route 
author
+  controls is by design.
+- A finding in `karavan-vscode` is in model **only if** it is triggered by 
opening a
+  workspace, not by the developer's own explicit command invocation. 
*(maintainer, 2026-09 — §4.14 Q10)*
+
+---
+
+## 4.5 Assumptions about the environment
+
+- **Runtime.** JVM 21, Quarkus. *(documented — `karavan-devmode/Dockerfile` 
uses
+  `ubi9/openjdk-21`; `karavan-app/pom.xml`.)*
+- **Persistence.** A PostgreSQL instance, reachable and trusted. Flyway 
migrates the
+  schema at startup. *(documented — `application.properties`.)* The database is
+  assumed to be on a private network; Karavan does not encrypt its own rows.
+  *(maintainer, 2026-09 — §4.14 Q5)*
+- **Container platform.** Exactly one of: a Docker daemon reachable at
+  `/var/run/docker.sock`, or a Kubernetes API server with the `karavan` 
service account
+  bound to the `karavan` `Role`. Karavan selects the mode at runtime.
+  *(documented — `ConfigService.inKubernetes()`, `docs/install/`.)*
+- **Git remote.** A reachable Git repository that Karavan owns. Karavan treats 
it as the
+  single source of truth and will import whatever it finds there into its own 
state.
+  *(documented — `README.md`; `ProjectService.importProject`.)*
+- **Network.** Karavan assumes it sits on a trusted network. It does not 
terminate TLS
+  itself; the reference Helm chart offers an optional ingress TLS block that 
defaults
+  off. *(documented — `docs/install/karavan-helm/templates/ingress.yaml`, 
`values.yaml`.)*
+- **Clock.** Session and API-token expiry are wall-clock comparisons against
+  `Instant.now()`. A backwards clock jump extends credential lifetime. 
*(maintainer, 2026-09 —
+  §4.14 Q5)*
+- **Concurrency.** The API is stateless per request; shared state lives in
+  `KaravanCache` backed by PostgreSQL. No claim is made about behaviour under 
concurrent
+  writes to the same project file — last write wins. *(maintainer, 2026-09 — 
§4.14 Q5)*
+
+### What Karavan does *not* do to its host
+
+These are **negative claims**, almost never written down anywhere. The 
maintainers have
+confirmed each is accurate today but have **not** committed to them as 
invariants — "that
+is just how it is today and we do not have any plans to change that". Treat 
them as an
+accurate description of the current release rather than a promise a future one 
will keep,
+and re-verify them whenever §4.12 is triggered. *(maintainer, 2026-09 — §4.14 
Q5)*
+
+- Does **not** install signal handlers or otherwise mutate process-global 
state beyond
+  what Quarkus itself does. *(maintainer, 2026-09 — §4.14 Q5)*
+- Does **not** spawn child processes on the Karavan host. All execution is 
delegated to
+  the container platform; there is no `Runtime.exec` / `ProcessBuilder` in
+  `karavan-app`. *(maintainer, 2026-09 — §4.14 Q5; verified by absence in the 
source tree)*
+- Does **not** read arbitrary host filesystem paths. It reads only its own 
classpath
+  resources and the two operator-configured SSH paths 
(`karavan.private-key-path`,
+  `karavan.known-hosts-path`), plus Vert.x temp directories for Git clones. 
*(maintainer, 2026-09 — §4.14 Q5)*
+- Does **not** listen on any port other than the configured HTTP port. 
*(maintainer, 2026-09 — §4.14 Q5)*
+- **Does** read environment variables and MicroProfile Config values, and 
**exposes both
+  to authenticated callers** via `/ui/diagnostics/*` — see §4.9. *(documented —
+  `DiagnosticResource`)*
+- **Does** write to the configured Git remote and image registry on user 
action.
+  *(documented)*
+
+---
+
+## 4.5a Build-time and configuration variants
+
+Karavan is not one binary with one security posture; it is a family of 
deployments.
+These knobs change which properties in §4.8 hold.
+
+| Knob | Default | Effect on the model | Maintainer stance |
+| --- | --- | --- | --- |
+| `platform.auth` | `session` | `session` uses Karavan's own bcrypt user store 
and cookie sessions. `oidc` delegates to Keycloak and takes roles from the 
access token. *(documented — `application.properties`, 
`CookieSessionAuthMechanism`)* | Both are supported. *(maintainer, 2026-09)* |
+| `quarkus.oidc.tenant-enabled` | `false` | **Must be flipped to `true` when 
`platform.auth=oidc`.** The property file says so in a comment. If 
`platform.auth=oidc` is set without it, `CookieSessionAuthMechanism` returns 
null and OIDC is disabled — the resulting posture is undefined. *(documented — 
`application.properties` comment: "Important! Set 
`quarkus.oidc.tenant-enabled=true` for `platform.auth=oidc`")* | Operator 
responsibility; a deployment that sets one without the other is misc [...]
+| `platform.password` | `K@r@v@n422` | Seeds the `admin` and `developer` 
accounts on first start. Intended to be set at install time through Kubernetes 
secrets or Docker environment variables, and changed afterwards through the UI. 
*(documented — `AuthService.loadDefaults`, `docs/WEB_DOCKER.md`, 
`docs/WEB_KUBERNETES.md`)* | **A dev/install convenience, not a supported 
production posture.** A report against the shipped default is `OUT-OF-MODEL: 
non-default-build`. *(maintainer, 2026-09)* |
+| `quarkus.security.jaxrs.deny-unannotated-endpoints` | `true` | 
Deny-by-default on the JAX-RS surface: an endpoint with no security annotation 
is refused rather than exposed. Flipping it to `false` voids the §4.8 
authorization property wholesale. *(documented — `application.properties`)* | 
Must stay `true`. *(maintainer, 2026-09)* |
+| `quarkus.http.auth.permission.public.paths` | 
`/public/*,/static/*,/robots.txt,/favicon.ico`, GET only | The unauthenticated 
surface. Widening it moves the §4.4 boundary. *(documented)* | The listed 
surface is deliberate, pre-login SSO disclosure included. *(maintainer, 
2026-09)* |
+| `quarkus.kubernetes-client.trust-certs` | `true` | Disables TLS certificate 
verification against the Kubernetes API server. Suits minikube; means Karavan 
will not detect a MitM on the API-server connection. *(documented — 
`application.properties`)* | Operator responsibility. *(maintainer, 2026-09)* |
+| `ingress.tls` (Helm) | `false` | Session cookies are marked `secure`, so 
with TLS off the browser will not send them — login effectively requires TLS or 
a plaintext-localhost origin. *(documented — `values.yaml`, `AuthResource`)* | 
Operator responsibility. *(maintainer, 2026-09)* |
+| `karavan.devmode.createm2` | `false` | When true, adds a named Docker volume 
per project for the Maven repository. Cross-project cache sharing implications. 
*(documented — `DockerForKaravan`)* | Not security-relevant under §4.7 — all 
projects share one trust domain. *(maintainer, 2026-09)* |
+| `configuration/build.sh` | ships with `-Djib.allowInsecureRegistries=true` | 
Permits pushing built images to a registry over plaintext HTTP. Suits the 
bundled `registry:2`. *(documented — 
`karavan-app/src/main/resources/configuration/docker/build.sh`)* | Operator 
responsibility. *(maintainer, 2026-09)* |
+| `karavan.deployment.allowed-kinds` | 
`Deployment,Service,ConfigMap,Secret,Ingress` | Restricts which resource kinds 
a project's `kubernetes.yaml` may apply, and rejects pod specs asking for 
`hostNetwork`, `hostPID`, `hostIPC`, `hostPath` volumes, `hostPort`, 
`privileged`, `allowPrivilegeEscalation`, or added capabilities. Namespace is 
pinned to Karavan's own regardless of what the file says. Added post-4.22.0. 
*(documented — `KubernetesService.validateDeploymentResource`, `validatePodS 
[...]
+| `KARAVAN_FLYWAY_ACTIVE`, `KARAVAN_HIBERNATE_ORM_ACTIVE` | `true` | Disabling 
either leaves the schema unmanaged. Not security-relevant on its own. 
*(documented)* | n/a |
+
+---
+
+## 4.6 Assumptions about inputs
+
+Karavan is a service, so the table is keyed by route rather than by function. 
"Attacker"
+below means the §4.7 adversary — an **unauthenticated** peer.
+
+| Route / input | Element | Attacker-controllable? | Operator/user must 
enforce |
+| --- | --- | --- | --- |
+| `POST /ui/auth/login` | `username`, `password` body | **yes** | Non-default 
`platform.password`; TLS in front |
+| `POST /ui/auth/logout` | `sessionId` cookie | **yes** | — |
+| `GET /ui/auth/type`, `/ui/auth/sso-config` | none | **yes (reachable)** | 
Accepts that auth mode, Keycloak URL, realm and public client ID are disclosed 
pre-auth *(documented — `@PermitAll` on both)* |
+| `GET /public/readiness` | none | **yes (reachable)** | Accepts that infra 
health and `karavan.environment` are disclosed pre-auth |
+| `GET /platform/internal/sources/{projectId}` | `sessionId` cookie, 
`projectId` | **yes (reachable)** — `@PermitAll`, gated by manual 
`authService.validateSession` | Network isolation between the Karavan 
pod/container and untrusted peers *(documented — `InternalResource`)* |
+| `Authorization: Bearer` / `X-API-Key` | raw token | **yes** | Token expiry; 
revocation via `/ui/access/tokens/{hashedToken}` |
+| All `/ui/**` bodies and path params | project ids, file names, file 
contents, container commands | **no — trusted route-author input** | Never 
grant a Karavan login to anyone who may not run code on the host |
+| `docker-compose.yaml` in a project | image, `volumes` (incl. `bind`), ports, 
`command` | **no — trusted.** Reaches `MountType.valueOf(...)` and `/bin/sh -c` 
*(documented — `DockerService.createContainer`)* | — |
+| `configuration/build.sh` | whole shell script, copied into the builder 
container with mode `0755` and executed *(documented — 
`DockerForKaravan.runBuildProject`)* | **no — trusted** | — |
+| `configuration/builder.pod.jkube.yaml` | full pod spec applied to the 
cluster | **no — trusted** | — |
+| Git repository contents | project folders, files, commit metadata | **no — 
trusted source of truth** *(documented — `README.md`; 
`ProjectService.importProjectFromRepo`)* | Restrict write access to the repo to 
the same population that may log into Karavan |
+| Container image registry | images pulled for `packaged` containers | **no — 
trusted** | Registry access control |
+
+**Size, shape and rate:** Karavan documents no limits on project count, file 
size, number
+of concurrent devmode containers, or request rate. *(maintainer, 2026-09 — 
§4.14 Q7)*
+
+---
+
+## 4.7 Adversary model
+
+**The adversary in scope is the unauthenticated network peer** who can reach 
Karavan's
+HTTP port. Their goal is to obtain an authenticated identity — because an 
authenticated
+identity is, by design, equivalent to code execution on the host. 
*(maintainer, 2026-09 — §4.14 Q2)*
+
+Capabilities assumed:
+
+- Send arbitrary HTTP requests to every route, including `@PermitAll` ones.
+- Attempt credential guessing against `POST /ui/auth/login`.
+- Attempt to present forged or stolen `sessionId` cookies and API tokens.
+- Induce a logged-in user's browser to issue cross-origin requests (classic 
CSRF), or
+  get script to run in the Karavan origin (XSS) — **whether these are in the 
model is
+  §4.14 Q9, and it is the most consequential open question in this document.**
+- Observe network traffic when TLS is absent.
+
+Capabilities **not** assumed:
+
+- Access to the host filesystem, the Docker socket, or the Kubernetes API.
+- Write access to the Git repository or the image registry.
+- Ability to read the PostgreSQL database directly.
+- Precise timing side-channel measurement against bcrypt or token comparison.
+  *(maintainer, 2026-09 — §4.14 Q9)*
+
+**Actors explicitly out of the model:**
+
+- **Any authenticated Karavan user, at any role.** They are the Camel security 
model's
+  "route author", which that model declares fully trusted. They can start a 
container
+  with `/var/run/docker.sock` bind-mounted, or edit `configuration/build.sh`. 
Reports of
+  the form "an authenticated user can achieve RCE" are `OUT-OF-MODEL:
+  adversary-not-in-scope`. *(documented — the Camel security model places 
"route author
+  code writing expressions over untrusted input" out of scope; extended here 
to Karavan
+  by inference — §4.14 Q2)*
+- **The operator.** Misconfiguration is theirs; see §4.10.
+- **A co-tenant on the Docker host or in the Kubernetes namespace.** They 
already share
+  Karavan's privilege domain.
+- **A compromised Git remote or image registry.** Both are trusted inputs. 
*(maintainer, 2026-09 —
+  §4.14 Q3)*
+- **An authenticated user attacking another user's project.** There is no 
isolation to
+  breach; see §4.9.
+
+---
+
+## 4.8 Security properties Karavan provides
+
+Each property states the conditions under which it holds, what a violation 
looks like,
+and whether a violation is security-critical or a correctness bug.
+
+**1. Deny-by-default authorization on the HTTP API.** *(documented —
+`quarkus.security.jaxrs.deny-unannotated-endpoints=true`; every `/ui/*` 
resource
+method carries `@Authenticated`, `@RolesAllowed`, or `@PermitAll`.)*
+*Conditions:* `deny-unannotated-endpoints` left at `true`, public path list 
unwidened.
+*Violation symptom:* any state-changing or data-returning endpoint outside the 
§4.6
+`@PermitAll` list answers a request bearing no valid session and no valid 
token.
+*Severity:* **security-critical.**
+
+**2. The unauthenticated surface is limited to the §4.6 list.** *(documented — 
the
+`@PermitAll` annotations and `quarkus.http.auth.permission.public.*`)*
+*Conditions:* as above.
+*Violation symptom:* an unauthenticated caller reads project data, container 
status,
+logs, environment variables, Kubernetes secrets, or user records.
+*Severity:* **security-critical.**
+
+**3. Passwords are stored only as bcrypt hashes.** Cost factor 12. 
*(documented —
+`AuthService.COST = 12`, `BcryptUtil.bcryptHash`.)*
+*Conditions:* `platform.auth=session`. Under `oidc` Karavan stores no password 
at all.
+*Violation symptom:* a plaintext or reversibly-encoded password recoverable 
from the
+database, an API response, or a log line.
+*Severity:* **security-critical.**
+
+**4. Failed logins are counted and the account locks.** After more than five 
failed
+attempts the account is refused until reset; a `lockedUntil` timestamp is 
honoured.
+*(documented — `AuthService.login`.)*
+*Conditions:* `platform.auth=session`.
+*Violation symptom:* unbounded password guessing against one account.
+*Severity:* **security-critical.**
+
+**5. Session identifiers, CSRF tokens and API tokens are unguessable.** 32 
bytes,
+16 bytes and 32 bytes respectively from `SecureRandom`, base64url-encoded.
+*(documented — `AuthService.random`, `AccessResource.generateToken`.)*
+*Violation symptom:* a token or session id predictable from another, or from 
time.
+*Severity:* **security-critical.**
+
+**6. API tokens are stored hashed, never in plaintext.** SHA-256; the raw 
token is
+returned to the creator once and never again; incoming tokens are hashed 
before lookup.
+*(documented — `AccessResource.generateToken`, 
`TokenAuthenticationMechanism`.)*
+*Violation symptom:* a usable raw token recoverable from the database or from
+`GET /ui/access/tokens`.
+*Severity:* **security-critical.**
+
+**7. API tokens expire.** Default 30 days, operator-selectable at creation; 
expiry is
+checked on every request and an expired token degrades to anonymous. 
*(documented —
+`AccessToken.isExpired`, `TokenAuthenticationMechanism`.)*
+*Violation symptom:* an expired token still authenticates.
+*Severity:* **security-critical.**
+
+**8. Session cookies are `HttpOnly` and `Secure`, and expire after 12 hours.**
+*(documented — `AuthResource.login`, `AuthService.SESSION_MAX_AGE`.)*
+*Violation symptom:* the `sessionId` cookie readable from JavaScript, sent over
+plaintext HTTP, or accepted past its lifetime.
+*Severity:* **security-critical.**
+
+**9. The builder's bootstrap session is short-lived and single-use for the 
sources
+endpoint.** `ProjectService.buildProject` mints a non-persisted session, 
passes it to the
+builder container as an environment variable, and 
`InternalResource.getProjectFiles`
+invalidates it in a `finally` block. *(documented.)*
+*Conditions:* applies to `GET /platform/internal/sources/{projectId}`.
+*Violation symptom:* the same builder session id usable a second time on that 
endpoint.
+*Severity:* **security-critical.**
+*Note:* the sibling route `GET 
/platform/internal/sources/{projectId}/{filename}` does
+**not** invalidate its session, **by design** — the single-use guarantee is 
scoped to the
+whole-project route only, and a report that the per-file route reuses a 
session is
+`BY-DESIGN: property-disclaimed`. *(maintainer, 2026-09 — corrects the first 
draft, which
+proposed this was an oversight.)*
+
+**10. User, role, session and token administration is admin-only.** Every 
mutating
+endpoint under `/ui/access` carries `@RolesAllowed({ROLE_ADMIN})`, except 
token creation
+which also admits `ROLE_DEVELOPER` and self-service profile update which admits
+`ROLE_USER`. *(documented — `AccessResource`.)*
+*Violation symptom:* a non-admin creates a user, changes another user's role 
or password,
+or lists sessions.
+*Severity:* **security-critical.**
+
+**11. Changing a password invalidates the caller's session cookie and requires 
the
+current password.** *(documented — `AuthResource.setPassword` calls 
`authService.login`
+first, then clears the cookie.)*
+*Violation symptom:* password change without knowledge of the current password.
+*Severity:* **security-critical.**
+
+**12. Git operations use the operator-supplied credential, never a 
user-supplied one.**
+Users cannot direct Karavan at an arbitrary remote or supply their own 
credentials
+through the API. *(documented — `GitService.setCredentials` reads only
+`karavan.git.*` / `karavan.private-key-path`.)*
+*Violation symptom:* an API path that causes Karavan to authenticate to a 
remote of the
+caller's choosing.
+*Severity:* **security-critical** (credential exfiltration).
+
+**13. Cookie-authenticated state-changing requests are CSRF-protected.** Every 
unsafe
+method (anything but `GET`/`HEAD`/`OPTIONS`/`TRACE`) carrying a `sessionId` 
cookie must
+also carry the session's token in an `X-CSRF-Token` header. This is the 
synchronizer-token
+check — the header is compared against the token held server-side on the 
session, not
+against the `csrf` cookie, so a token planted by an attacker controlling a 
sibling
+subdomain does not satisfy it. Comparison is constant-time. Logout is 
deliberately **not**
+exempt; only `ui/auth/login` is, having no session to bind to yet. 
*(documented —
+`CsrfFilter`, added post-4.22.0 in `d211d71f`.)*
+*Conditions:* `platform.auth=session` only. Bearer/API-key requests are exempt 
— a browser
+never attaches those on its own — as are requests whose session belongs to a 
builder or
+devmode container rather than a user.
+*Violation symptom:* a cross-origin page causes a state change using only the 
victim's
+ambient session cookie.
+*Severity:* **security-critical.**
+
+**14. Project ids and file names are validated before use as path segments.** 
Rejected if
+empty, containing `..`, `/`, `\`, or NUL, or not matching 
`^[a-zA-Z0-9_\-.]+$`. Enforced
+on file create, update, rename and copy. *(documented — 
`PathUtils.validateName`,
+`ProjectFileResource`; added post-4.22.0 in `5e425249`.)*
+*Conditions:* covers the `/ui/file` write paths.
+*Violation symptom:* a project id or file name that escapes its parent 
directory on disk
+or in the Git working copy.
+*Severity:* **security-critical.**
+
+---
+
+## 4.9 Security properties Karavan does *not* provide
+
+**This is the section a downstream operator most needs.** None of the 
following are
+defects; they are the shape of the product.
+
+### No isolation between authenticated users
+
+- **There is no per-project authorization.** Almost every functional endpoint 
is
+  annotated `@Authenticated` with no role constraint. Any account — including 
a bare
+  `platform-user` — can list, read, modify, copy and delete **every** project 
and
+  project file, start and stop **any** devmode container, trigger builds, roll 
out and
+  delete **any** deployment, and stream **any** container's logs. *(documented 
— the
+  annotation survey across `ProjectResource`, `ProjectFileResource`, 
`DevModeResource`,
+  `ContainerResource`, `InfrastructureResource`, `StatusResource`, 
`LogWatchResource`.)*
+- **The `platform-user` / `platform-developer` / `platform-admin` roles do not 
tier
+  functional access.** They gate only the `/ui/access` administration surface. 
See
+  "false friends" below.
+- **API-token project scoping is recorded but not enforced.** 
`allowedProjectIds` is
+  stored on the token and attached to the identity as an attribute, but no 
endpoint
+  reads it. A token scoped to one project has the same reach as one scoped to 
`*`.
+  *(maintainer, 2026-09 — `grep` finds no consumer of the `allowedProjectIds` 
identity attribute;
+  §4.14 Q4)*
+- **Username path parameters are not checked against the caller.**
+  `/ui/notification/user/{username}` and 
`/ui/logwatch/{type}/{name}/{username}` take a
+  username from the path. *(maintainer, 2026-09 — §4.14 Q4)*
+
+### No confidentiality of platform configuration from authenticated users
+
+- `GET /ui/diagnostics/env-vars` and `/ui/diagnostics/app-props` enumerate 
every
+  environment variable and MicroProfile Config key, and the `/{name}` variants 
return
+  the **values** — base64-wrapped, which is encoding, not protection. Any 
authenticated
+  user can therefore read `KARAVAN_GIT_PASSWORD`, 
`KARAVAN_DATASOURCE_PASSWORD`,
+  `karavan.container-image.registry-password`, and the Keycloak backend secret.
+  *(documented — `DiagnosticResource`.)*
+- `GET /ui/infrastructure/secrets` returns Kubernetes `Secret` objects from the
+  namespace to any authenticated user. *(documented — 
`InfrastructureResource`.)*
+
+Both are consistent with the trust model — a route author who can bind-mount 
the host
+already has these — but they must not be mistaken for protected surfaces.
+
+### No sandbox around user-authored deployment artifacts
+
+- A project's `docker-compose.yaml` controls image, `bind` mounts, published 
ports and a
+  `/bin/sh -c` command. *(documented — `DockerService.createContainer`,
+  `DockerComposeConverter`.)*
+- `configuration/build.sh` is an ordinary project file, editable through 
`/ui/file`, that
+  is copied into the builder container mode `0755` and executed for every 
build.
+  *(documented — `CodeService.getConfigurationText`, 
`DockerForKaravan.runBuildProject`.)*
+- `configuration/builder.pod.jkube.yaml` is likewise a user-editable pod spec 
applied to
+  the cluster.
+
+Post-4.22.0, the **Kubernetes deployment path alone** gained a validation 
pass: a project's
+`kubernetes.yaml` may only carry the kinds in 
`karavan.deployment.allowed-kinds`, its pod
+specs may not request `hostNetwork`, `hostPID`, `hostIPC`, `hostPath`, 
`hostPort`,
+`privileged`, `allowPrivilegeEscalation` or added capabilities, and the 
namespace is pinned
+to Karavan's own. *(documented — 
`KubernetesService.validateDeploymentResource`.)*
+**This is defence in depth against a careless route author, not a security 
boundary**, and
+it must not be read as one: it does not cover the builder pod path
+(`KubernetesService.runBuildProject`), `configuration/build.sh`, or any part 
of the Docker
+path, where a compose file still controls image, bind mounts, ports and the 
shell command.
+A user who wants host access simply uses one of those instead. *(maintainer, 
2026-09 —
+§4.14 Q2 confirms the trust model this sits inside.)*
+
+### No transport or platform hardening
+
+- **Karavan does not terminate TLS.** The reference Helm chart defaults 
`ingress.tls` to
+  `false`; the reference compose file publishes `8080` in the clear.
+- **No rate limiting** on login or on any other endpoint beyond the 
per-account lockout.
+- **No quota** on containers, builds, projects, or file sizes.
+- **No audit log of security-relevant events.** `ActivityFilter` publishes 
presence and
+  project-touch events to an event bus for the UI's "who is working on what" 
display; it
+  is telemetry, not an audit trail. *(maintainer, 2026-09 — §4.14 Q12)*
+- **No secret redaction in logs.** *(maintainer, 2026-09 — §4.14 Q12)*
+- **No constant-time comparison** outside bcrypt's own verification and the 
CSRF token
+  check. API-token lookup is a hash-map hit on a SHA-256 digest.
+
+### False friends — things that look like security controls but are not
+
+| Looks like | Actually is |
+| --- | --- |
+| **`component-blocklist.txt` (344 entries)** | A **UI curation list**, not a 
security control. It is served to the designer to hide components, it lives in 
the user-editable `configuration` project *(documented — 
`webui/src/services/ProjectService.ts`)*, and nothing in the backend or in 
`karavan-devmode` refuses to *run* a blocklisted component. Do not treat it as 
an allow-list enforcement point. |
+| **`platform-admin` / `platform-developer` / `platform-user`** | A three-tier 
RBAC scheme that tiers **only** `/ui/access`. It is not a functional privilege 
ladder; see above. |
+| **`Secure` / `HttpOnly` on the session cookie** | Cookie attributes, not TLS 
enforcement. Karavan will happily run without TLS; the browser then simply 
declines to send the cookie. |
+| **The `platform-service-account` role** | Never appears in any 
`@RolesAllowed`. It is a label, not a restriction; a token satisfies 
`@Authenticated` everywhere. *(maintainer, 2026-09 — §4.14 Q4)* |
+| **SHA-256 hashing of API tokens** | Storage protection against database 
disclosure. It is a fast unsalted digest, appropriate here only because the 
token is 32 bytes of `SecureRandom` — it would be inadequate for anything 
low-entropy. |
+| **Git as "source of truth"** | An availability and history mechanism. It is 
not integrity verification: commits are not signed or verified, and whatever is 
in the repo is imported as trusted code. *(maintainer, 2026-09 — §4.14 Q3)* |
+
+### Well-known attack classes Karavan does not defend against
+
+- **Stored XSS** in the designer, if any project-file content is rendered as 
HTML. The
+  designer's content is route-author input, so under the trust model this is
+  self-inflicted; it becomes interesting only if it crosses between users, 
which — given
+  the absence of project isolation — it would. *(maintainer, 2026-09 — §4.14 
Q9)*
+  (CSRF was on this list in the first draft. It is now defended — see §4.8 
property 13.)
+- **Supply-chain substitution of `karavan.devmode.image`** — the devmode image 
tag is an
+  operator-set config value and is pulled and run without digest pinning.
+- **SSRF via Camel components** inside a running route — Camel's model, not 
Karavan's.
+- **Credential stuffing** across the shared `admin` account.
+
+---
+
+## 4.10 Operator responsibilities
+
+This is a contract, not a tutorial. For Karavan's model to hold, the operator 
must:
+
+1. **Set `platform.password` at install time** — through a Kubernetes secret 
or a Docker
+   environment variable — and change it afterwards through the UI. The shipped 
default is
+   an install convenience, not a supported production posture, so running on 
it is the
+   operator's own risk rather than a Karavan defect. *(maintainer, 2026-09 — 
§4.14 Q1)*
+2. **Put Karavan behind TLS.** Session cookies are `Secure`; without TLS, 
login does not
+   work off `localhost` anyway. Set `ingress.tls: true` and `tlsSecretName` in 
the Helm
+   values.
+3. **Never expose Karavan to an untrusted network.** Treat the HTTP port as 
you would a
+   Jenkins controller or a Kubernetes dashboard.
+4. **Grant a Karavan login only to people you would grant root on the Docker 
host, or
+   admin on the Kubernetes namespace.** There is no lesser tier. This is the 
single most
+   important line in this document.
+5. **Scope the Git credential to Karavan's own repository.** Karavan hands
+   `GIT_USERNAME` / `GIT_PASSWORD` to every build container's `git credential 
approve`
+   *(documented — `karavan-devmode/entrypoint.sh`)*. A broadly-scoped PAT is 
exposed to
+   anything running there.
+6. **Scope the registry credential to Karavan's own image group**, for the 
same reason —
+   it is passed as `-Djib.to.auth.password` on a Maven command line inside the 
builder.
+7. **Network-isolate `/platform/internal/*`** from anything but Karavan's own 
build and
+   devmode containers.
+8. **When setting `platform.auth=oidc`, also set 
`quarkus.oidc.tenant-enabled=true`.**
+   The property file says so; nothing enforces it.
+9. **Reconsider `quarkus.kubernetes-client.trust-certs=true`** for any cluster 
that is
+   not a local minikube.
+10. **Rotate and revoke API tokens.** They default to 30 days and to `*` 
project scope,
+    and the scope is not enforced (§4.9).
+11. **Restrict write access to the Git repository** to exactly the population 
allowed to
+    log into Karavan — a repo write is equivalent to an authenticated Karavan 
action.
+12. **Review `configuration/build.sh` and `configuration/builder.*.yaml`** as 
you would
+    review CI pipeline definitions. They are executable code, and any Karavan 
user can
+    change them.
+
+---
+
+## 4.11 Known misuse patterns
+
+- **Exposing Karavan on the public internet, or on a broad corporate 
network.** *What it
+  looks like:* an ingress without an auth proxy, or a `NodePort`. *Why it is 
unsafe:* the
+  only thing between an anonymous peer and host-level code execution is one 
password
+  form with a shipped default. *Instead:* private network plus VPN or an 
authenticating
+  reverse proxy.
+- **Running with the shipped `admin` password.** *Instead:* set 
`platform.password`, or
+  use `platform.auth=oidc`.
+- **Treating Karavan roles as a permission tier.** *What it looks like:* 
granting
+  `platform-user` to contractors on the theory that it is read-only. *Why it 
is unsafe:*
+  `platform-user` can start a container with an arbitrary image, an arbitrary 
bind mount
+  and an arbitrary shell command. *Instead:* run separate Karavan instances 
per trust
+  group.
+- **Treating Karavan as multi-tenant.** *What it looks like:* several teams 
sharing one
+  instance and expecting project separation. *Why it is unsafe:* every project 
is visible
+  and writable to every account. *Instead:* one instance per team.
+- **Handing Karavan an organisation-wide Git PAT or registry credential.** 
*Why it is
+  unsafe:* the credential is materialised inside every build container. 
*Instead:* a
+  deploy key or a repo-scoped token.
+- **Setting `platform.auth=oidc` and stopping there.** *Why it is unsafe:*
+  `quarkus.oidc.tenant-enabled` is still `false`, so the intended mechanism 
does not
+  engage. *Instead:* set both.
+- **Reading `component-blocklist.txt` as a security control.** *Why it is 
unsafe:* it is
+  a UI hint in a user-editable file. *Instead:* if a component must not run, 
do not give
+  the person a Karavan account.
+- **Copying `docs/install/*` into production unmodified.** *Why it is unsafe:*
+  placeholder credentials, TLS off, PostgreSQL published on `5432`, registry 
published on
+  `5555`. *Instead:* treat them as a getting-started illustration.
+
+---
+
+## 4.11a Known non-findings (recurring false positives)
+
+These are what scanners, secret detectors and AI reviewers report against 
Karavan that
+are **not** bugs given this model. Suitable for use verbatim as a suppression 
list.
+
+- **"Hardcoded credentials in `application.properties`"** — 
`platform.password`,
+  `karavan.git.password`, `karavan.datasource.password`,
+  `karavan.keycloak.backend.secret`. These are development defaults for a 
self-contained
+  local stack, overridden by `KARAVAN_*` environment variables in every 
documented
+  deployment. `platform.password` is the same: an install-time convenience 
that operators
+  set via secret or environment variable and then change through the UI, so a 
report
+  against the shipped default is `OUT-OF-MODEL: non-default-build`. 
*(maintainer, 2026-09)*
+- **"Hardcoded credentials in `docs/install/karavan-helm/values.yaml` /
+  `karavan-kubernetes/secret.yaml`"** — placeholder values in reference 
manifests. Out of
+  scope per §4.3.
+- **"Command injection: `/bin/sh -c` in `DockerService.createContainer`"** — 
the command
+  originates from a project's `docker-compose.yaml`, which is trusted 
route-author input
+  per §4.6. Not reachable by the §4.7 adversary.
+- **"Arbitrary file write / host bind mount via `MountType.valueOf(...)`"** — 
same origin,
+  same disposition.
+- **"Arbitrary script execution: `build.sh` copied at mode 0755 and 
executed"** — same;
+  `configuration/build.sh` is trusted input.
+- **"Overly permissive RBAC: `verbs: ["*"]` and `pods/exec` in `role.yaml`"** 
— the
+  privilege Karavan requires to do its job, namespace-scoped. §4.3.
+- **"Docker socket mounted into a container"** — likewise, and documented as 
such in the
+  compose file's own comment. §4.3.
+- **"Insecure registry: `-Djib.allowInsecureRegistries=true`"** — targets the 
bundled
+  in-cluster `registry:2`. A §4.5a knob in a user-editable file.
+- **"TLS verification disabled: 
`quarkus.kubernetes-client.trust-certs=true`"** — a
+  §4.5a knob with a minikube-oriented default; report against it as a 
*default* choice,
+  not as a code defect (§4.14 Q6).
+- **"Authenticated user can reach privileged functionality"** — by design; 
§4.7. Includes
+  every report of the form "logged-in user achieves RCE / reads secrets / 
deletes another
+  project".
+- **"Base64 used for encoding secrets in `DiagnosticResource`"** — base64 is 
transport
+  encoding here and is not claimed as protection; the underlying disclosure is 
disclaimed
+  in §4.9.
+- **"Unpinned container image `karavan.devmode.image`"** — an operator 
configuration
+  value; §4.9.
+- **"Missing CSRF protection"** against a route that is safe 
(`GET`/`HEAD`/`OPTIONS`/
+  `TRACE`), token-authenticated, or `ui/auth/login` — all three are 
deliberately exempt
+  from `CsrfFilter`. §4.8 property 13.
+- **"Path traversal in project id / file name"** on the `/ui/file` write paths 
—
+  `PathUtils.validateName` rejects `..`, separators, NUL and anything outside
+  `^[a-zA-Z0-9_\-.]+$` before the value is used. §4.8 property 14.
+- **"Unrestricted Kubernetes resource application"** in `startDeployment` — 
kinds are
+  allow-listed and host-level pod options rejected. This is *not* claimed as a 
boundary
+  (§4.9), so a report that it is bypassable via the builder pod or the Docker 
path is
+  `OUT-OF-MODEL: adversary-not-in-scope`, not a control bypass.
+- **Third-party CVEs in transitive dependencies** with no demonstrated path 
from the §4.7
+  adversary to a §4.8 property. §4.3.
+
+---
+
+## 4.12 Conditions that would change this model
+
+Revise when any of these happens — not for internal refactors:
+
+- **A per-project or per-user authorization layer is added**, or 
`allowedProjectIds`
+  becomes enforced. This would move most of §4.9's first block into §4.8 and 
make
+  cross-project access a `VALID` finding.
+- **Karavan gains a supported multi-tenant or internet-facing deployment 
mode.**
+- **A new unauthenticated endpoint is added**, or the `@PermitAll` /
+  `quarkus.http.auth.permission.public.paths` set is widened.
+- **`quarkus.security.jaxrs.deny-unannotated-endpoints` is changed**, or a new
+  authentication mechanism is registered alongside the two in `api/`.
+- **The `CsrfFilter` exemption set changes** — a new exempt path, or unsafe 
methods no
+  longer requiring the token.
+- **`PathUtils` validation is relaxed**, or a new write path bypasses it.
+- **`karavan.deployment.allowed-kinds` is widened**, or the pod-spec 
restrictions in
+  `validatePodSpec` are relaxed — and note §4.9 does not treat these as a 
boundary, so
+  widening them is a posture change rather than a vulnerability.
+- **The default of a §4.5a knob changes** — above all `platform.password` and
+  `platform.auth`.
+- **Karavan begins accepting input from a party other than an authenticated 
user or its
+  own Git remote** — a webhook receiver, an inbound event API, a public 
template gallery.
+- **`karavan-generator` or the VS Code extension is promoted into the server's 
runtime
+  path.**
+- **A report arrives that cannot be routed to exactly one §4.13 disposition.** 
That is
+  evidence of a `MODEL-GAP`; the correct response is to add the property to 
§4.8 or §4.9,
+  not to make an ad-hoc call.
+
+---
+
+## 4.13 Triage dispositions
+
+A report, tool finding, or AI analysis judged against this model receives 
exactly one of:
+
+| Disposition | Meaning | Licensed by |
+| --- | --- | --- |
+| `VALID` | Violates a §4.8 property, reachable by the §4.7 adversary through 
a §4.6 attacker-controllable input. | §4.6, §4.7, §4.8 |
+| `VALID-HARDENING` | No §4.8 property is violated, but a §4.11 misuse is made 
easy enough that Karavan elects to harden. Fixed at maintainer discretion; 
normally no CVE. | §4.11 |
+| `OUT-OF-MODEL: trusted-input` | Requires control of an input §4.6 marks 
trusted — a project file, `build.sh`, a compose file, the Git repo, the 
registry. | §4.6 |
+| `OUT-OF-MODEL: adversary-not-in-scope` | Requires an authenticated Karavan 
session, an operator action, or host/cluster access. **The most common 
disposition.** | §4.7 |
+| `OUT-OF-MODEL: unsupported-component` | Lands in `karavan-generator/`, 
`release-utils/`, `docs/install/*`, or repo dev tooling. | §4.3 |
+| `OUT-OF-MODEL: non-default-build` | Only manifests under a non-default or 
discouraged §4.5a setting. | §4.5a |
+| `OUT-OF-MODEL: camel-core` | Concerns a running route, a Camel component, or 
exchange data — the Apache Camel security model's territory. Route to 
`apache/camel`. | §4.3 |
+| `BY-DESIGN: property-disclaimed` | Concerns a property §4.9 explicitly does 
not provide, including the false friends. | §4.9 |
+| `KNOWN-NON-FINDING` | Matches a documented recurring false positive. | 
§4.11a |
+| `MODEL-GAP` | Routes to none of the above. Escalate; revise the model. | 
triggers §4.12 |
+
+---
+
+## 4.14 Open questions for the maintainers
+
+Waves 1–3 were answered by @mgubaidullin on 2026-09-01 in 
apache/camel-karavan#1642 and
+are folded into the body above; the resolution log is Appendix B. Two 
questions remain,
+both about the document rather than about Karavan.
+
+**Q13. Where should this document live, and how does it relate to the Camel 
security
+model?** The Camel security model at 
`camel.apache.org/manual/security-model.html` scopes
+itself to `apache/camel` artifacts and notes that sibling subprojects have 
their own
+security surfaces; Karavan is not named. *Proposed:* this becomes Karavan's 
own model, is
+linked from the Camel security page's subproject list, and inherits Camel's 
role
+vocabulary without restating it. Karavan has no `SECURITY.md` — should one be 
added
+pointing at `[email protected]` and at this file, and should Karavan be 
added to the ASF
+security site's `project-coordinates.json`? → lands in §4.1.
+
+**Q14. Who owns revisions, and does the model ship with releases?** 
*Proposed:* the
+Karavan committers own it; it is updated in the same PR as any change that 
trips a §4.12
+trigger, and is tagged with each release so a report against 4.22.0 is triaged 
against the
+4.22.0 model. This revision already spans two versions — it is bound to `main` 
after
+4.22.0, and three of its properties do not exist in the 4.22.0 release — which 
is exactly
+the drift the tagging policy is meant to prevent. → lands in §4.1, §4.12.
+
+---
+
+## Appendix A — back-map to the Apache Camel security model
+
+Karavan has no `SECURITY.md` of its own. The nearest maintainer-authored 
security policy
+in the Camel family is the Apache Camel security model. It does not claim 
Karavan, but
+this model deliberately inherits its vocabulary so that a triager moving 
between the two
+does not have to re-derive the roles.
+
+| Camel security model statement | Where it lands here |
+| --- | --- |
+| Applies to artifacts released from `apache/camel`; sibling subprojects have 
their own security surfaces | §4.3 — establishes that Karavan needs this 
document; §4.14 Q13 |
+| Trust boundary separates the route and operator configuration from the data 
flowing through the route | §4.4 — Karavan's boundary sits one layer earlier, 
at HTTP authentication |
+| Route authors are fully trusted and may execute arbitrary code | §4.2, §4.7 
— extended to "any authenticated Karavan user" |
+| Deployment operators are fully trusted | §4.2, §4.10 |
+| External message senders are the primary adversary | §4.3 — out of Karavan's 
model; that is Camel's adversary, not Karavan's |
+| Operator misconfiguration (TLS disabled, exposed management surfaces) is out 
of scope | §4.3, §4.10 — Karavan takes the same position |
+| Denial of service through resource exhaustion is out of scope | §4.3, §4.14 
Q7 |
+| Management surface operations (JMX, Jolokia, developer console) are out of 
scope | §4.9 — Karavan's `/ui/diagnostics` and devmode console are the analogue 
|
+| Transitive third-party CVEs are out of scope | §4.3, §4.11a |
+| Non-default settings requiring explicit opt-in are out of scope | §4.5a, 
§4.13 `OUT-OF-MODEL: non-default-build` |
+| Hardening advice: explicit `prod` profile, vaults for secrets, TLS via 
SSLContextParameters, least privilege | §4.10 — Karavan's operator contract is 
the parallel list |
+
+---
+
+## Appendix B — resolution log
+
+Answers from @mgubaidullin, 2026-09-01, on apache/camel-karavan#1642. Kept so 
that a
+future reader can see which claims were ratified rather than assumed, and so 
that a
+reporter who disputes a disposition can be pointed at the ruling behind it.
+
+| # | Question | Outcome | Landed in |
+| --- | --- | --- | --- |
+| Q1 | Is the default `platform.password` a supported production posture? | 
**Confirmed as proposed** — install-time convenience, set via secret/env and 
changed through the UI. Reports against it are `OUT-OF-MODEL: 
non-default-build`. | §4.5a, §4.10, §4.11a |
+| Q2 | Is any authenticated user fully trusted? | **Confirmed** — yes. | §4.2, 
§4.7, §4.9 |
+| Q3 | Are the Git repository and image registry trusted inputs? | 
**Confirmed** — yes, fully trusted. | §4.3, §4.6, §4.7 |
+| Q4 | Is API-token project scoping meant to be enforced? | **Confirmed** — 
forward-looking scaffolding for future features, not a current guarantee. | 
§4.9 |
+| Q5 | Are the negative side-effect claims deliberate guarantees? | 
**Confirmed accurate, but not promised** — "that is just how it is today and we 
do not have any plans to change that". Recorded as description, not invariant. 
| §4.5 |
+| Q6 | Which §4.5a defaults are supported posture? | **Confirmed** — insecure 
defaults are operator responsibility; reports against them are out of model. | 
§4.5a |
+| Q7 | Where is the line on resource consumption? | **Confirmed** — DoS and 
resource exhaustion are out of model. | §4.3, §4.9 |
+| Q8 | What is the intended unauthenticated surface? | **Confirmed** — 
pre-login disclosure of Keycloak/SSO config is by design. | §4.5a, §4.6 |
+| Q9 | Is the browser an adversary channel, and is CSRF unvalidated? | 
**Superseded — fixed.** `CsrfFilter` (`d211d71f`) added synchronizer-token 
validation after 4.22.0. Promoted from a §4.9 false friend to §4.8 property 13. 
| §4.8, §4.9 |
+| Q10 | Is opening an untrusted workspace in the VS Code extension supported? 
| **Confirmed** — malicious workspaces/repos are out of model. | §4.2.1, §4.4 |
+| Q11 | Is the non-invalidating `/sources/{projectId}/{filename}` route an 
oversight? | **Corrected** — it is by design. The first draft's proposed answer 
was wrong. | §4.8 property 9 |
+| Q12 | Is there meant to be an audit trail? | **Confirmed** — no; 
`ActivityFilter` is telemetry, and the absence of audit is by design. | §4.9 |
+| Q13, Q14 | Document ownership and revision policy | **Open.** | §4.14 |
+
+Two changes to the code landed alongside the answers and are described in the 
body:
+`PathUtils` name validation (`5e425249`, §4.8 property 14) and the Kubernetes 
resource
+allow-list plus pod-spec restrictions (§4.5a, §4.9). Neither existed in 4.22.0.

Reply via email to