This is an automated email from the ASF dual-hosted git repository.

shreemaan-abhishek pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git


The following commit(s) were added to refs/heads/master by this push:
     new cd61deb397 fix(request-validation): guard non-string Content-Type 
before lower() (#13691)
cd61deb397 is described below

commit cd61deb3976fae44153d20a16d86643ea218e9c3
Author: Shreemaan Abhishek <[email protected]>
AuthorDate: Wed Jul 15 17:03:38 2026 +0800

    fix(request-validation): guard non-string Content-Type before lower() 
(#13691)
---
 apisix/plugins/request-validation.lua | 13 +++++-
 t/plugin/request-validation.t         | 76 ++++++++++++++++++++++++++++++++++-
 2 files changed, 85 insertions(+), 4 deletions(-)

diff --git a/apisix/plugins/request-validation.lua 
b/apisix/plugins/request-validation.lua
index ae5e352ab3..02f2f51c3a 100644
--- a/apisix/plugins/request-validation.lua
+++ b/apisix/plugins/request-validation.lua
@@ -18,6 +18,7 @@ local core          = require("apisix.core")
 local secret        = require("apisix.secret")
 local plugin_name   = "request-validation"
 local ngx           = ngx
+local type          = type
 
 local schema = {
     type = "object",
@@ -89,9 +90,17 @@ function _M.rewrite(conf, ctx)
         end
 
         local body_is_json = true
-        if headers["content-type"]
+        local content_type = headers["content-type"]
+        -- a duplicated Content-Type is ambiguous: APISIX and the upstream may
+        -- parse the body differently, bypassing validation. reject it.
+        if type(content_type) == "table" then
+            core.log.error("duplicated Content-Type header")
+            return conf.rejected_code, conf.rejected_msg
+        end
+
+        if type(content_type) == "string"
             and core.string.has_prefix(
-                headers["content-type"]:lower(),
+                content_type:lower(),
                 "application/x-www-form-urlencoded"
             )
         then
diff --git a/t/plugin/request-validation.t b/t/plugin/request-validation.t
index fcb4407291..790ccdea71 100644
--- a/t/plugin/request-validation.t
+++ b/t/plugin/request-validation.t
@@ -1786,11 +1786,83 @@ qr/101-hello/
 
 
 
-=== TEST 53: test urlencoded post data with charset header
+=== TEST 53: test urlencoded post data with charset and mixed-case media type
 --- more_headers
-Content-Type: application/x-www-form-urlencoded; charset=utf-8
+Content-Type: Application/X-WWW-Form-Urlencoded; charset=utf-8
 --- request eval
 "POST /echo
 " . "a=b&" x 101 . "required_payload=101-hello"
 --- response_body eval
 qr/101-hello/
+
+
+
+=== TEST 54: add route for duplicated Content-Type validation
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/routes/1',
+                 ngx.HTTP_PUT,
+                 [[{
+                    "plugins": {
+                        "request-validation": {
+                            "body_schema": {
+                                "type": "object",
+                                "required": ["required_payload"],
+                                "properties": {
+                                    "required_payload": {"type": "string"}
+                                }
+                            },
+                            "rejected_code": 400,
+                            "rejected_msg": "duplicated content-type"
+                        }
+                    },
+                    "upstream": {
+                        "nodes": {
+                            "127.0.0.1:1980": 1
+                        },
+                        "type": "roundrobin"
+                    },
+                    "uri": "/echo"
+                }]])
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 55: duplicated Content-Type header is rejected (urlencoded, json)
+--- more_headers
+Content-Type: application/x-www-form-urlencoded
+Content-Type: application/json
+--- request
+POST /echo
+{"required_payload": "hello"}
+--- error_code: 400
+--- response_body chomp
+duplicated content-type
+--- error_log
+duplicated Content-Type header
+
+
+
+=== TEST 56: duplicated Content-Type header is rejected (json, urlencoded)
+--- more_headers
+Content-Type: application/json
+Content-Type: application/x-www-form-urlencoded
+--- request
+POST /echo
+{"required_payload": "hello"}
+--- error_code: 400
+--- response_body chomp
+duplicated content-type
+--- error_log
+duplicated Content-Type header

Reply via email to