Skip to content

UI encodes slashes in KV paths, causing 400 errors behind Traefik v3.6+ #31681

@RebootFixesAll

Description

@RebootFixesAll

Describe the bug
The Vault UI URL-encodes forward slashes (/) in KV secret paths, converting them to %2F. This causes compatibility issues with reverse proxies like Traefik v3.6.3+, which now block encoded slashes by default for security reasons. When accessing a KV secret with a path containing slashes (e.g., my-app/production/config), the UI generates encoded paths like:

/ui/vault/secrets/secret/kv/my-app%2Fproduction%2Fconfig

Instead of the expected:

/ui/vault/secrets/secret/kv/my-app/production/config

To Reproduce
Steps to reproduce the behavior:

  1. Deploy Vault behind Traefik v3.6.3+ with default settings
  2. Log into the Vault UI
  3. Navigate to a KV secrets engine
  4. Create a new secret with a path containing slashes (e.g., my-app/production/config)
  5. See 400 Bad Request error from Traefik due to encoded slashes in the request path

example logs

2025-12-17T20:10:14Z DBG github.com/traefik/traefik/v3/pkg/server/router/deny.go:52 > Rejecting request because it contains encoded character %2F in the URL path: /v1/secret/data/my-app%2Fproduction%2Fconfig

142.250.191.187 - - [17/Dec/2025:20:10:14 +0000] "POST /v1/secret/data/my-app%2Fproduction%2Fconfig HTTP/1.1" 400 0 "-" "-" 31 "vault@docker" "-" 0ms

Expected behavior

paths should not include encoded characters

Environment:

  • Vault Server Version: (any recent version)
  • Vault CLI Version: (any recent version)
  • Server Operating System/Architecture: Linux/amd64
  • Reverse Proxy: Traefik v3.6.3+

Additional context
Traefik v3.6.3 introduced security restrictions that block requests containing encoded characters in the path by default, including %2F (encoded slash). See: https://doc.traefik.io/traefik/v3.6/security/request-path/ While users can work around this by setting allowEncodedSlash: true in Traefik configuration, this reduces security posture. Ideally, the Vault UI would not encode slashes that are legitimate path separators.

docker compose for testing and verification

services:
  traefik:
    image: traefik:v3.6.5
    ports:
      - "80:80"
      - "8080:8080"
    command:
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--log.level=DEBUG"
      - "--accesslog=true"
      - "--accesslog.format=common"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro

  vault:
    platform: linux/x86_64
    image: hashicorp/vault:1.21
    ports:
      - '8200:8200'
    environment:
      - VAULT_DEV_ROOT_TOKEN_ID=dev-only-token
    volumes:
      - vault_data:/vault/data
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.vault.rule=Host(`localhost`)"
      - "traefik.http.routers.vault.entrypoints=web"
      - "traefik.http.services.vault.loadbalancer.server.port=8200"

volumes:
  vault_data:

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions