{
  "variant_outcome": "confirmed_distinct_variant_no_bypass",
  "variant_type": "alternate_trigger",
  "variant_confirmed": true,
  "bypass_confirmed": false,
  "bypass_tested_on_fixed": true,
  "fixed_version": "gitlab/gitlab-ce:19.3.2-ce.0 (digest sha256:05453dd1d9aba27c2c487613141596868409b4d03247647f7d66cb0b36f321b8, gitlab-rails 34042bf7d00ca54c5e04079df6cdc6151485fd46)",
  "vulnerable_version": "gitlab/gitlab-ce:19.3.1-ce.0 (digest sha256:f63df4c43029fe91db370609c0b40a1e3585cebd06e3e9637d93a9a3030eb86e, gitlab-rails 668508315ee5b5a59aa018424f741c27e81bafe1)",
  "variant_summary": "Distinct alternate trigger confirmed on the vulnerable build: POST/PUT /api/v4/projects/<id>/repository/files/<segment>/ (trailing slash defeats workhorse's anchored regex ^/api/v4/projects/[^/]+/repository/files/[^/]+\\z while Grape still routes the path) reaches lib/api/files.rb create/update-file endpoints, which in 19.3.1 call require_gitlab_workhorse! but NOT authenticate!, and feed the raw request parameter file.path into the same file_params_from_body_upload sink (File.exist?/File.read) as the parent CVE - full canary content echoed unauthenticated. Corroborating encoding variant: POST /api/v4/projects/<id>/repository/commits/ (trailing slash instead of .json) reproduces the parent entry point. No bypass: every tested entry point returns 401 Unauthorized on the fixed 19.3.2 build in both runs.",
  "validated_surface": "api_remote",
  "evidence_scope": "production_path",
  "claimed_impact_class": "info_leak",
  "observed_impact_class": "info_leak",
  "exploitability_confidence": "high",
  "attacker_controlled_input": "Unauthenticated POST (or PUT) http://target/api/v4/projects/<id>/repository/files/<any-segment>/?file=&file.size=64&Content-Type=application/x-www-form-urlencoded&file.path=<arbitrary filesystem path> with HTTP header Content-Type: application/x-www-form-urlencoded and empty body",
  "trigger_path": "nginx -> gitlab-workhorse (clean path .../repository/files/vfile.txt/ does not match ^/api/v4/projects/[^/]+/repository/files/[^/]+\\z, raw proxy with signed Gitlab-Workhorse header) -> Rails/Grape routes trailing-slash path -> API::Files post/put ':id/repository/files/:file_path' (19.3.1: require_gitlab_workhorse! only, no authenticate!) -> CommitsBodyUploaderHelper#file_params_from_body_upload -> File.exist?/File.read(params['file.path']) -> Rack::Utils.parse_nested_query(file content) -> Rack::QueryParser::InvalidParameterError message echoed in 400 response",
  "end_to_end_target_reached": true,
  "read_write_primitive_observed": true,
  "exploit_chain_demonstrated": true,
  "sanitizer_used": false,
  "crash_observed": false,
  "inferred": false,
  "blocking_mitigation": "v19.3.2 fix (authenticate! added to commits.rb post ':id/repository/commits', files.rb post/put ':id/repository/files/:file_path', and workhorse_authorize_commits_body_upload!; file_params_from_body_upload accepts only middleware-finalized ::UploadedFile) blocks all tested variant entry points on the fixed build - verified live on 19.3.2-ce.0 with 401 responses for commits .json, commits trailing-slash, files POST/PUT trailing-slash, files plain/.json, and both /authorize.json probes.",
  "negative_results": [
    "No bypass on fixed 19.3.2: all eight matrix entries return 401 with no file-content echo and no existence oracle.",
    "Repository Files API plain path and .json suffix (single-segment tail) are intercepted by workhorse (pre-authorized, body finalized to empty tempfile) and do not read the attacker path (400 'branch is required') - only the trailing-slash form defeats classification.",
    "All other workhorse-accelerated routes audited in source (uploads, wikis attachments, alert metric images, jobs artifacts/sbom scans, project/group import, placeholder reassignments, terraform state, packages, avatars, web /uploads and /import routes) enforce their own authentication in both 19.3.1 and 19.3.2; terraform/packages regexes are prefix-anchored and not suffix/trailing-slash defeatable.",
    "GET /api/v4/geo/proxy is workhorse-only without authenticate! but exposes only Geo proxy configuration (EE-only, no file access) - different sink, not claimed as a variant."
  ],
  "matrix_results_ref": "bundle/logs/vuln_variant/matrix_results.json",
  "runs": 2,
  "idempotent": true,
  "script_exit_code": 1
}
