{
  "claim_outcome": "alternate_trigger_confirmed_vulnerable_only",
  "bypass_confirmed": false,
  "variant_confirmed": true,
  "variant_kind": "alternate_trigger",
  "repro_result": "alternate_trigger_on_vulnerable_not_bypass_on_fixed",
  "validated_surface": "api_remote",
  "evidence_scope": "production_path",
  "claimed_impact_class": "code_execution",
  "observed_impact_class_vulnerable": "code_execution",
  "observed_impact_class_fixed": "none",
  "exploitability_confidence": "high",
  "attacker_controlled_input": "Unauthenticated HTTP: (1) POST /api/v1/main/flows/configs with a YAML flow body whose namespace=id=configs and which carries an io.kestra.plugin.core.trigger.Webhook trigger (attacker-chosen key) plus an io.kestra.plugin.scripts.shell.Commands task; (2) GET /api/v1/main/executions/webhook/configs/configs/<key> to trigger it.",
  "trigger_path": "AuthenticationFilter.doFilter -> isOpenUrl branch (request.getPath().startsWith(open-url)) is TRUE for /api/v1/main/executions/webhook/... because the production-default open-urls include that prefix. The isOpenUrl branch is NOT modified by fix 28ff533d8. The webhook request reaches ExecutionController.triggerExecutionByGetWebhook unauthenticated, which executes the attacker-created flow's shell task in the worker. The CREATE step still uses the /configs suffix bypass (isConfigEndpoint) on the vulnerable version; the TRIGGER step uses the open-url webhook branch (isOpenUrl) -- a different whitelist branch and a different controller endpoint than the parent repro (isConfigEndpoint + ExecutionController /trigger).",
  "end_to_end_target_reached": true,
  "rce_observed_vulnerable": true,
  "rce_observed_fixed": false,
  "fixed_blocks_creation": true,
  "fixed_webhook_path_still_open": true,
  "sanitizer_used": false,
  "crash_observed": false,
  "read_write_primitive_observed": false,
  "exploit_chain_demonstrated": true,
  "blocking_mitigation": "Fix 28ff533d8 closes the /configs suffix bypass for flow CREATION (POST /api/v1/main/flows/configs -> 401 on fixed). Because the attacker can no longer create the malicious flow unauthenticated on the fixed version, the open-webhook trigger has no flow to execute (404 'Flow not found', not 401) and no RCE occurs. The open-url webhook branch itself remains open on fixed/latest (documented behavior).",
  "rule_out_matrix": {
    "configs_exact_match_edge_cases": {
      "double_slash_api_v1//configs": "404 (whitelisted by normalizePath but unroutable -> harmless)",
      "trailing_slash_api_v1_configs/": "401 (exact match fails -> not whitelisted)",
      "encoded_slash_api_v1_main_flows%2Fconfigs": "401 (not a /configs whitelist bypass)",
      "verdict": "no_bypass"
    },
    "basicAuth_regex_setup_state": {
      "GET_/api/v1/flows/basicAuth_one_segment": "200 (whitelisted during setup; routes via aliasing to FlowController namespace=basicAuth READ -> negligible)",
      "GET_/api/v1/main/namespace/basicAuth_two_segments": "401 (fix regression-test case -> closed)",
      "POST_/api/v1/flows/basicAuth": "422 (routes to MiscController createBasicAuth setup endpoint, NOT FlowController create -> not a create bypass)",
      "verdict": "no_normal_operation_bypass"
    },
    "openurl_webhook_branch": {
      "vulnerable_GET_webhook": "200 + RCE marker (alternate trigger confirmed)",
      "fixed_GET_webhook": "404 not 401 (branch still open, flow not found -> no RCE)",
      "verdict": "alternate_trigger_vulnerable_only_not_bypass"
    }
  },
  "inferred": false,
  "notes": "The variant is an ALTERNATE TRIGGER on the vulnerable version that exercises a different AuthenticationFilter whitelist branch (isOpenUrl/startsWith, untouched by the fix) and a different ExecutionController endpoint (/webhook) than the parent repro (isConfigEndpoint + /trigger). It is NOT a bypass: on the fixed version the /configs create-bypass is closed so the attacker cannot plant the flow, and the open webhook returns 404. The open-url webhook being unauthenticated is documented behavior (webhook key is the secret); the security-relevant takeaway is that the fix only hardened isConfigEndpoint and the unauthenticated execution-trigger surface via isOpenUrl persists on fixed/latest as a defense-in-depth gap."
}
