nginx / nginx/nginx

feature: adding a configuration flag to set whether NGiNX should decode percent-encoded characters in URI or not

Open
#501 6 comments 1 reaction 1 assignee View on GitHub

@pluknet is already working on this.

Since Apr 28, 2026.

feature needs-analysis
Dominant language
C
Stars
31.7k
Forks
8.3k
Avg merge
1d 12h
Merged PRs (30d)
13

Description

[!NOTE]

I'm not a security expert and I don't know if that feature might generate vulnerabilities or anything similar (e.g. path traversal attacks). If that's the case, you can directly close or delete the issue, but I'd love to be redirected to some relevant documentation on the topic and/or to receive some guidance on how to approach this task in the correct way 🙂

Describe the feature you'd like to add to nginx

I'd like to introduce a configuration flag named decode_percent_characters (or something similar):

  • by default set to on, so that it doesn't change NGiNX default behaviour;
  • similarly to merge_slashes, it's passed to ngx_http_parse_complex_uri();
  • if set to off, NGiNX doesn't replace percent-encoded characters in request URIs, with their respective decoded values (i.e. %2f doesn't get decoded to / if we set decode_percent_characters off; in nginx.conf);
Example
Show/Hide example

Suppose we compiled Nginx from source (files located at /usr/local/nginx/) and we are serving 2 pages:

  • /usr/local/nginx/html/path%2fslash/index.html:

    Path: path%2fslash/
    
  • /usr/local/nginx/html/path/slash/index.html:

    Path: path/slash/
    
Before this feature

Nginx config file (/usr/local/nginx/conf/nginx.conf):

worker_processes  1;

events {
  worker_connections  1024;
}

http {
  server {
    listen       80;
    server_name  localhost;
  }
}

Test requests:

  1. Encoded slash:

    $ curl localhost/path%2fslash/
    Path: path/slash/
    
  2. Slash:

    $ curl localhost/path/slash/
    Path: path/slash/
    

Logs (/usr/local/nginx/logs/access.log):

127.0.0.1 - - [28/Apr/2026:15:42:59 +0200] "GET /path/slash/ HTTP/1.1" 200 18 "-" "curl/8.5.0"
127.0.0.1 - - [28/Apr/2026:15:42:59 +0200] "GET /path/slash/ HTTP/1.1" 200 18 "-" "curl/8.5.0"

NB: It always returns the page at path/slash (%2f is automatically decoded to / before matching the route).

With new feature
worker_processes  1;

events {
  worker_connections  1024;
}

http {
  decode_percent_characters off;
  
  server {
    listen       80;
    server_name  localhost;
  }
}

Test requests:

  1. Encoded slash:

    $ curl localhost/path%2fslash/
    Path: path%2fslash/
    
  2. Slash:

    $ curl localhost/path/slash/
    Path: path/slash/
    

Logs (/usr/local/nginx/logs/access.log):

127.0.0.1 - - [28/Apr/2026:15:43:54 +0200] "GET /path%2fslash/ HTTP/1.1" 200 20 "-" "curl/8.5.0"
127.0.0.1 - - [28/Apr/2026:15:43:57 +0200] "GET /path/slash/ HTTP/1.1" 200 18 "-" "curl/8.5.0"

NB: it serves the correct pages.

Describe the problem this feature solves

With this feature, we would be able to serve pages containing percent-encoded characters in their path (e.g. /usr/local/nginx/html/path%2fslash/index.html).

Additionally, when NGiNX is used as a reverse proxy, such as when it's distributed via OpenResty and used as an API Gateway (e.g. APISIX, Kong, etc.), we can match routes that have path parameters containing percent-encoded characters, and delegate their decoding to upstreams/other web servers.
Notice that many popular web frameworks already support percent-encoded characters in path parameters:

Technology Supports %-encoded chars Usage Docs
Django (Python) 🟢 Using <path:id> Django - Path Converters
Fastapi (Python) 🟢 Using {id:path} Fastapi - Path Convertor
Flask (Python) 🟢 Using <path:id> Flask - Variable Rules
Express (JS) 🟢 Using :id (default) Express - Route Parameters
Fastify (JS) 🟢 Using :id (default) Fastify - URL Building
Actix Web (Rust) 🟢 Using {id} (default) Actix - Resource Pattern Syntax
ASP.NET Core (C#) 🟢 Using {id} (default) ASP.NET - Route Templates
Spring (Java) 🟢 By default requests containing %2F in path parameters return 400: Bad Request, but Tomcat can be configured to allow them Spring MVC - URI Patterns
NGiNX (C) 🔴 - -
Additional context
Some References
Feature Implementation

I already implemented two versions of this feature in a fork:

APISIX Example

With this feature, we could make APISIX correctly match routes containing %-encoded characters in path parameters (when using router radixtree_uri_with_parameters, see APISIX Docs | Router), by simply setting the following configuration in /apisix/path/conf/config.yaml:

nginx_config:
  http_configuration_snippet: |
    decode_percent_characters off;
OpenResty

Maybe there's a simpler way to handle this via OpenResty ngx_http_lua_module?

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.