{
  "schema": "sosec.gitlab-85706.parser.v1",
  "observed_at": "2026-09-20",
  "cve": "CVE-2026-85706",
  "scope": "Parser-only execution; response bodies constructed from inspected helper format, not captured GitLab HTTP responses",
  "runtime": {
    "ruby": "ruby 3.3.3 (2024-06-12 revision f1c7b6f435) [wasm32-wasi]",
    "bundled_uri": "0.13.0",
    "loaded_decoder": "ruby/uri v1.1.1: both decoder methods evaluated verbatim",
    "rack": "2.2.23"
  },
  "method": {
    "input_origin": "Synthetic strings only; no external requests or sensitive files.",
    "execution": "Rack QueryParser source executed with a minimal Rack::Utils.unescape delegation and the two exact URI 1.1.1 decoder methods.",
    "response_examples": "Constructed with JSON.generate and the inspected GitLab helper error format. They are not HTTP captures.",
    "excluded": [
      "Full GitLab runtime",
      "Workhorse-to-Rails routing",
      "Filesystem permissions",
      "Real deployments",
      "End-to-end exploitation"
    ]
  },
  "sources": {
    "gitlab_vulnerable": "https://gitlab.com/gitlab-org/gitlab/-/blob/9d55961fa804344fb1a988c503bd36f31f0f6f0f/lib/api/helpers/commits_body_uploader_helper.rb#L17-47",
    "gitlab_fix": "https://gitlab.com/gitlab-org/gitlab/-/commit/0ff7b6b2911723389f2271b10362591b0a69a166",
    "dependency_lock": "https://gitlab.com/gitlab-org/gitlab/-/blob/9d55961fa804344fb1a988c503bd36f31f0f6f0f/Gemfile.lock",
    "rack_parser": "https://github.com/rack/rack/blob/f2af0c8f869193fa7bb7d20b619b3003418e1055/lib/rack/query_parser.rb",
    "rack_unescape": "https://github.com/rack/rack/blob/f2af0c8f869193fa7bb7d20b619b3003418e1055/lib/rack/utils.rb#L57-L58",
    "uri_decoder": "https://github.com/ruby/uri/blob/f1b05c89ab38667e7564896f994d4d6cfbc67149/lib/uri/common.rb#L430-L466"
  },
  "results": [
    {
      "name": "invalid-value",
      "input": "note=calm&token=DEMO%oops&tail=ok",
      "error_class": "Rack::QueryParser::InvalidParameterError",
      "parser_error": "invalid %-encoding (DEMO%oops)",
      "old_response_example": "{\"message\":\"400 Bad request - Invalid parameter: invalid %-encoding (DEMO%oops)\"}",
      "fixed_response_example": "{\"message\":\"400 Bad request - Invalid parameter\"}",
      "input_bytes": 33,
      "old_response_bytes": 81
    },
    {
      "name": "valid-escape",
      "input": "note=calm&token=DEMO%25oops&tail=ok",
      "result": {
        "note": "calm",
        "token": "DEMO%oops",
        "tail": "ok"
      }
    },
    {
      "name": "no-delimiter",
      "input": "DEMO%oops",
      "error_class": "Rack::QueryParser::InvalidParameterError",
      "parser_error": "invalid %-encoding (DEMO%oops)",
      "old_response_example": "{\"message\":\"400 Bad request - Invalid parameter: invalid %-encoding (DEMO%oops)\"}",
      "fixed_response_example": "{\"message\":\"400 Bad request - Invalid parameter\"}",
      "input_bytes": 9,
      "old_response_bytes": 81
    },
    {
      "name": "semicolon",
      "input": "note=calm;token=DEMO%oops;tail=ok",
      "error_class": "Rack::QueryParser::InvalidParameterError",
      "parser_error": "invalid %-encoding (DEMO%oops)",
      "old_response_example": "{\"message\":\"400 Bad request - Invalid parameter: invalid %-encoding (DEMO%oops)\"}",
      "fixed_response_example": "{\"message\":\"400 Bad request - Invalid parameter\"}",
      "input_bytes": 33,
      "old_response_bytes": 81
    }
  ]
}
