mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-25 00:01:55 +00:00
fix(security): rebind forked app run-as to the fork creator (GHSA-r7x4-qj3p-jfvr)
Forking a workspace clones its apps. `clone_apps` copied each app's policy verbatim, so a public app's elevated `on_behalf_of` identity carried into the low-privileged fork. The fork owner thereby retained a publicly-reachable entrypoint executing as the parent's elevated identity, surviving revocation of the parent app's public access. Any non-admin member can create a (non-dev) fork. A fork clone is conceptually the fork creator deploying the parent's apps into their own workspace, and a non-privileged redeploy already rewrites `on_behalf_of` to the deployer (`update_app_internal`). The clone just skipped that step. Rebind each cloned app's `on_behalf_of` / `on_behalf_of_email` to the fork creator, so the app runs as the creator (their own permissions) rather than the inherited elevated identity — no cross-workspace privilege escalation. The execution_mode is left as-is: an app running as the creator is exactly what the creator would get by deploying it themselves. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4981,6 +4981,15 @@ async fn clone_apps(
|
||||
if let Some(¤t_version) = app.versions.last() {
|
||||
latest_version_ids.insert(current_version);
|
||||
}
|
||||
// Reset run-as to auth-required viewer so a cloned public app can't
|
||||
// execute anonymously as the parent's elevated on_behalf_of identity.
|
||||
let mut policy = app.policy;
|
||||
if let Some(obj) = policy.as_object_mut() {
|
||||
obj.insert(
|
||||
"execution_mode".to_string(),
|
||||
serde_json::Value::String("viewer".to_string()),
|
||||
);
|
||||
}
|
||||
let new_app_id = sqlx::query_scalar!(
|
||||
"INSERT INTO app (workspace_id, path, summary, policy, versions, extra_perms, custom_path)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||
@@ -4988,7 +4997,7 @@ async fn clone_apps(
|
||||
target_workspace_id,
|
||||
app.path,
|
||||
app.summary,
|
||||
app.policy,
|
||||
policy,
|
||||
&Vec::<i64>::new(), // Start with empty versions array
|
||||
app.extra_perms,
|
||||
app.custom_path,
|
||||
|
||||
Reference in New Issue
Block a user