Skip to content

chore: add draft threat model - #1642

Open
oscerd wants to merge 1 commit into
mainfrom
docs/threat-model
Open

chore: add draft threat model#1642
oscerd wants to merge 1 commit into
mainfrom
docs/threat-model

Conversation

@oscerd

@oscerd oscerd commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

What this is

A first draft of a threat model for Karavan, at docs/threat-model.md.

It is deliberately not an audit, a pentest report, or a findings list. It describes
the implicit contract between Karavan and the people who deploy it: what Karavan
assumes, what it guarantees given those assumptions, what it leaves to the operator,
and which misuses look reasonable but aren't. The audience is two-sided — an operator
deciding how to deploy Karavan, and a triager who has to classify an inbound
vulnerability report or a scanner hit and cite a section to justify the call.

Why now

Karavan has no SECURITY.md, and no entry in the ASF security site's
project-coordinates.json.
The Apache Camel security model
scopes itself to apache/camel artifacts and explicitly notes that sibling subprojects
"have their own security surfaces" — Karavan isn't named. So today there is nothing a
triager can cite when a report or an automated scan lands.

The draft inherits Camel's role vocabulary (route author / operator / external message
sender) rather than inventing a parallel one, and Appendix A back-maps all eleven of
that document's statements to sections here.

The claim the document turns on

The trust boundary is HTTP authentication, and nothing after it. A Karavan account
is Camel's "route author", which that model declares fully trusted. Docker mode
bind-mounts /var/run/docker.sock; Kubernetes mode grants verbs: ["*"] on secrets,
configmaps, serviceaccounts, pods and deployments plus pods/exec; a project's
docker-compose.yaml reaches MountType.valueOf(...) and /bin/sh -c; and
configuration/build.sh is a user-editable file copied into the builder at mode 0755
and executed.

If that's right, then "an authenticated user achieves RCE" is OUT-OF-MODEL: adversary-not-in-scope, and §4.11a lists it as a suppression entry alongside the
docker.sock mount, the wildcard RBAC, and the application.properties credentials that
every secret scanner flags. Q2 below is asking you to confirm exactly that.

Provenance

Written from public artifacts only — no maintainer input yet. Every non-trivial claim
carries a tag:

53 (documented) · 0 (maintainer) · 28 (inferred)

(inferred) means hypothesis, not yet confirmed. Each one routes to a numbered
question in §4.14. Please don't read the draft as asserting these — they're the ask.

The ask — wave 1 (blocking)

Each states a proposed answer. Confirm, correct, or strike — a one-line reply per
question is enough, and I'll fold the answers in and promote the tags.

Q1 — the default admin password. platform.password=K@r@v@n422 seeds admin and
developer. The project's own artifacts point both ways: AuthService.loadDefaults
reads as a getting-started convenience, but 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. Is the default the supported
production posture (making default-credential reports VALID), or a dev convenience
operators are expected to override (making them OUT-OF-MODEL: non-default-build, and
making the install docs a gap to close)?

Q2 — is "any authenticated user is fully trusted" the intended model? Proposed:
yes
— a Karavan account is Camel's route author, so one user reaching another's project
is not a vulnerability, and the absence of per-project authorization is a scope decision
rather than a gap. This is the load-bearing question; most of §4.9 and the whole triage
table in §4.13 depend on it.

Q3 — are the Git repository and the image registry trusted inputs? Proposed: yes
Karavan imports whatever the repo holds as code, doesn't verify commit signatures, and
pulls images by tag. A malicious repo or registry is outside the adversary model.

Q4 — is API-token project scoping meant to be enforced? allowedProjectIds is
persisted, documented in AccessToken as "Scoped access limits (ABAC)", and attached to
the identity — but I can't find an endpoint that reads it. Related: ROLE_SERVICE_ACCOUNT
appears in no @RolesAllowed, and /ui/notification/user/{username} and
/ui/logwatch/{type}/{name}/{username} take a username from the path without comparing
it to the caller. Proposed: forward-looking scaffolding rather than a current
guarantee, and §4.9 should say so plainly.

Q5 — the negative side-effect inventory. Proposed: on its own host, karavan-app
installs no signal handlers, spawns no child processes (no Runtime.exec /
ProcessBuilder anywhere in the module), reads no host paths beyond its classpath, the
two configured SSH files and Vert.x temp dirs, and listens on no port but the configured
HTTP one. Are those four deliberate guarantees, or just true today? These are negative
claims — almost never written down, and impossible to cite — so they're the
highest-value thing to confirm.

Waves 2–4

Nine more in §4.14, deliberately held back so wave 1 can be answered in one sitting:
resource limits and which §4.5a defaults are supported posture (Q6–Q8), browser-side
threats and the VS Code extension's workspace-trust assumption (Q9–Q12), and document
ownership and revision policy (Q13–Q14).

One item that may belong on security@ instead

Q9 observes that the csrf cookie is minted and stored on the session, but that I
found no server-side handler validating it against an incoming header. Either CSRF is in
the model and the check is missing, or the browser isn't an adversary channel and the
cookie should be removed so it stops reading as a control (§4.9 lists it under "false
friends" precisely because it's ambiguous today).

It's framed as a question rather than an exploit, and it's derivable from the public
source — but if you'd rather that one didn't get worked through in a public PR, say so
and I'll strip it from the draft and route it to security@apache.org instead.

Notes

  • New file only. Nothing else in the tree is touched, and the draft proposes no code
    changes — it describes Karavan as it is, not as it should be.
  • It runs ~9 pages against the rubric's suggested 3–8. A service with 23 JAX-RS resource
    classes and seven component families earns some of that, but I'd happily cut §4.8 or
    §4.11 down if you find it long.
  • Rubric: https://gist.github.com/potiuk/da14a826283038ddfe38cc9fe6310573

🤖 Generated with Claude Code

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) <noreply@anthropic.com>
@oscerd
oscerd force-pushed the docs/threat-model branch from b42af8b to b499cb9 Compare August 28, 2026 13:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant