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

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

commit b42af8b2e5923d141dcf9cee2755bfaf8f0b4a36
Author: Andrea Cosentino <[email protected]>
AuthorDate: Fri Aug 28 15:17:24 2026 +0200

    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]>
    Claude-Session: https://claude.ai/code/session_01LhQkuMMro7EkXxjU8XYryx
---
 docs/threat-model.md | 818 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 818 insertions(+)

diff --git a/docs/threat-model.md b/docs/threat-model.md
new file mode 100644
index 00000000..e0e1db2f
--- /dev/null
+++ b/docs/threat-model.md
@@ -0,0 +1,818 @@
+# Apache Camel Karavan — Threat Model
+
+| | |
+| --- | --- |
+| **Project** | Apache Camel Karavan |
+| **Version / commit** | 4.22.0 — `51247d48ba95b7d3461597845d7135cf95e27e5f` |
+| **Date** | 2026-08-28 |
+| **Status** | **DRAFT — not yet reviewed by maintainers.** Produced from 
public artifacts only. |
+| **Author** | Drafted with the ASF Security `threat-model-producer` rubric. |
+
+## 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.
+
+## 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. 
|
+| *(inferred)* | Reasoned from code structure or the absence of a feature. Not 
yet confirmed; has a matching question in §4.14. |
+
+## Draft confidence
+
+**53 documented / 0 maintainer / 28 inferred.** No claim in this draft has yet 
been
+ratified by a maintainer. The *(inferred)* claims concentrate in §4.5 (negative
+side-effect claims), §4.7 (adversary model), and §4.9 (disclaimed properties) 
— the
+three areas that are almost never written down and therefore matter most to 
confirm.
+Treat §4.14 wave 1 as blocking for publication.
+
+## 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.
+*(inferred — §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. *(inferred — §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. 
*(inferred
+  — §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. *(inferred — §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. *(inferred — §4.14 Q7)*
+- **Transitive third-party CVEs**, absent a demonstrated path from an in-scope 
adversary
+  to a Karavan-claimed property. *(inferred — §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. 
*(inferred — §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.
+  *(inferred — §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. 
*(inferred —
+  §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. *(inferred — §4.14 Q5)*
+
+### What Karavan does *not* do to its host
+
+These are **negative claims**, almost never written down anywhere, and 
therefore the
+highest-priority confirmation targets in §4.14 (Q5).
+
+- Does **not** install signal handlers or otherwise mutate process-global 
state beyond
+  what Quarkus itself does. *(inferred — §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`. *(inferred — §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. 
*(inferred — §4.14 Q5)*
+- Does **not** listen on any port other than the configured HTTP port. 
*(inferred — §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`)* | **Unresolved — §4.14 Q1** |
+| `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`")* | **Unresolved — 
§4.14 Q6** |
+| `platform.password` | `K@r@v@n422` | Seeds the `admin` and `developer` 
accounts on first start. **This is the insecure-default case.** The install 
docs link directly to the line in `application.properties` that holds it, and 
do not instruct the operator to change it. *(documented — 
`AuthService.loadDefaults`, `docs/WEB_DOCKER.md`, `docs/WEB_KUBERNETES.md`)* | 
**Unresolved — §4.14 Q1. This ruling decides whether "default admin 
credentials" is `VALID` or `OUT-OF-MODEL: non-default-build`.** |
+| `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`)* | 
**Unresolved — §4.14 Q8** |
+| `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)* | **Unresolved — 
§4.14 Q8** |
+| `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`)* | **Unresolved — §4.14 Q6** |
+| `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`)* | 
**Unresolved — §4.14 Q6** |
+| `karavan.devmode.createm2` | `false` | When true, adds a named Docker volume 
per project for the Maven repository. Cross-project cache sharing implications. 
*(documented — `DockerForKaravan`)* | **Unresolved** |
+| `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`)* | **Unresolved 
— §4.14 Q6** |
+| `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. *(inferred — §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. *(inferred — 
§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.
+  *(inferred — §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. 
*(inferred —
+  §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. Whether that is deliberate is §4.14 Q11.
+
+**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).
+
+---
+
+## 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 
`*`.
+  *(inferred — `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. *(inferred — §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.
+
+### 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. *(inferred — §4.14 Q12.)*
+- **No secret redaction in logs.** *(inferred — §4.14 Q12.)*
+- **No constant-time comparison** outside bcrypt's own verification. 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. |
+| **The `csrf` cookie** | Karavan mints a CSRF token, stores it on the 
session, and returns it in a JS-readable cookie — but **no server-side handler 
was found that validates it** against an incoming header. *(inferred — §4.14 
Q9.)* Its presence should not be read as evidence that CSRF is defended. |
+| **`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. *(inferred — §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. *(inferred — §4.14 Q3.)* |
+
+### Well-known attack classes Karavan does not defend against
+
+- **CSRF** against a logged-in operator's browser — see §4.14 Q9.
+- **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. *(inferred — §4.14 Q9.)*
+- **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. **Change `platform.password` before first start**, or delete the seeded 
`admin` and
+   `developer` accounts immediately after. The install docs ship a known 
default and link
+   to it. *(inferred — §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. **The one exception is `platform.password`**, whose default *is* 
the
+  documented first-login credential — that is §4.14 Q1 and is not settled.
+- **"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.
+- **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/`.
+- **CSRF validation is implemented**, or the `csrf` cookie is removed.
+- **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
+
+Every question below states a **proposed answer**. Confirm, correct, or strike 
it. When
+a question is answered, the matching *(inferred)* tags in the body are 
promoted to
+*(maintainer)* and the question is deleted.
+
+### Wave 1 — scope and the insecure default (blocking)
+
+**Q1. The default admin password.** *Proposed:* `platform.password=K@r@v@n422` 
seeding
+`admin` and `developer` is a getting-started convenience, and operators are 
expected to
+override it; a report of "default credentials" is therefore `OUT-OF-MODEL:
+non-default-build`. **However**, `docs/WEB_DOCKER.md` and 
`docs/WEB_KUBERNETES.md`
+present it as *the* first-login credential and link straight to the source 
line, with no
+instruction to change it. Which is it — supported production posture (making 
such reports
+`VALID`), or dev-only (making them out of model, and making the docs a gap to 
close)?
+→ lands in §4.5a, §4.10, §4.13.
+
+**Q2. Is "any authenticated user is fully trusted" the intended model?** 
*Proposed:* yes.
+A Karavan account is the Camel security model's "route author", declared fully 
trusted
+there; Karavan therefore does not treat one user attacking another as a 
vulnerability,
+and the absence of per-project authorization is a scope decision rather than a 
gap.
+→ lands in §4.2, §4.7, §4.9.
+
+**Q3. Are the Git repository and the image registry trusted inputs?** 
*Proposed:* yes.
+Karavan imports whatever the repo holds as code, does not verify commit 
signatures, and
+pulls images by tag. A malicious repo or registry is out of the adversary 
model.
+→ lands in §4.3, §4.6, §4.7.
+
+**Q4. Is API-token project scoping meant to be enforced?** `allowedProjectIds` 
is
+persisted on the token, documented in `AccessToken` as "Scoped access limits 
(ABAC)", and
+attached to the identity — but no endpoint reads it, and 
`ROLE_SERVICE_ACCOUNT` appears in
+no `@RolesAllowed`. Likewise `/ui/notification/user/{username}` and
+`/ui/logwatch/.../{username}` take a username from the path without comparing 
it to the
+caller. *Proposed:* these are forward-looking scaffolding, not current 
guarantees, and
+§4.9 should say so plainly. → lands in §4.8 or §4.9.
+
+**Q5. The negative side-effect inventory.** *Proposed:* on its own host, 
`karavan-app`
+installs no signal handlers, spawns no child processes, reads no host 
filesystem paths
+beyond its classpath, the two configured SSH files, and Vert.x temp 
directories, and
+listens on no port but the configured HTTP one. Are all four deliberate 
guarantees, or
+merely true today? Also: is the PostgreSQL connection assumed to be on a 
trusted network,
+and is any behaviour claimed for concurrent edits to the same project file?
+→ lands in §4.5.
+
+### Wave 2 — configuration variants and resource limits
+
+**Q6. Which §4.5a defaults are supported production posture?** Specifically:
+`quarkus.kubernetes-client.trust-certs=true`; Helm `ingress.tls: false`;
+`-Djib.allowInsecureRegistries=true` in the shipped `build.sh`; and the 
requirement to
+set `quarkus.oidc.tenant-enabled=true` alongside `platform.auth=oidc`. 
*Proposed:* all
+four are local-development conveniences that operators are expected to change, 
and the
+fourth should be enforced at startup rather than left to a comment. → lands in 
§4.5a,
+§4.10.
+
+**Q7. Where is the line on resource consumption?** *Proposed:* consistent with 
the Camel
+security model, DoS through resource exhaustion is out of scope, and there is 
no cap on
+concurrent devmode containers, builds, projects, file sizes, or request rate. 
Is an
+unauthenticated request that causes unbounded allocation nonetheless a bug? → 
lands in
+§4.3, §4.8.
+
+**Q8. What is the intended unauthenticated surface, exactly?** *Proposed:* 
precisely
+`/ui/auth/type`, `/ui/auth/sso-config`, `/ui/auth/login`, `/ui/auth/logout`,
+`/public/readiness`, `/platform/internal/sources/**`, and the static SPA 
assets — nothing
+else, ever. Is disclosing the Keycloak URL, realm and client ID 
pre-authentication
+intended? → lands in §4.6, §4.8.
+
+### Wave 3 — browser-side threats and operational surface
+
+**Q9. Is the browser an adversary channel?** The `csrf` cookie is minted and 
stored on
+the session, but no server-side validation of it was found. *Proposed (a):* 
CSRF is in the
+model, the validation is simply missing, and a working CSRF proof-of-concept 
against a
+state-changing `/ui/*` endpoint is `VALID`. *Proposed (b):* the browser is not 
an adversary
+channel at all, the cookie is vestigial, and it should be removed so it stops 
reading as a
+control. Which? The same question decides whether stored XSS in the designer 
is `VALID` or
+`BY-DESIGN`, and whether timing side channels are in scope. → lands in §4.7, 
§4.9.
+
+**Q10. Is opening an untrusted workspace in the VS Code extension supported?**
+*Proposed:* no — the extension assumes the developer trusts the workspace they 
open, in
+line with VS Code's own Workspace Trust model, and crafted Camel YAML in a 
cloned repo is
+out of scope. → lands in §4.2.1, §4.4.
+
+**Q11. Is the non-invalidating 
`/platform/internal/sources/{projectId}/{filename}` route
+deliberate?** Its sibling invalidates the builder session in a `finally` 
block; this one
+does not. *Proposed:* an oversight rather than a design choice, and §4.8 
property 9 should
+apply to both. → lands in §4.8.
+
+**Q12. Is there meant to be an audit trail?** *Proposed:* no. `ActivityFilter` 
is UI
+presence telemetry, not audit, and Karavan makes no claim about recording who 
deployed or
+deleted what, nor about redacting secrets from logs. If audit is intended, it 
belongs in
+§4.8. → lands in §4.9.
+
+### Wave 4 — document ownership
+
+**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 document becomes 
Karavan's own
+model, is linked from the Camel security page's subproject list, and inherits 
Camel's
+role vocabulary (route author / operator / external sender) without restating 
it.
+Karavan has no `SECURITY.md`; should one be added pointing at 
`[email protected]` and
+at this file? → 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 
hits §4.12's
+trigger list, and is tagged with each release so a report against 4.22.0 is 
triaged
+against the 4.22.0 model.
+
+---
+
+## 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 |

Reply via email to