Skip to content

TT-17508: Add restriction to absolute paths when base_path is provided#8322

Merged
vladzabolotnyi merged 13 commits into
masterfrom
fix/TT-17508/add-base-path-restrictions
Jun 18, 2026
Merged

TT-17508: Add restriction to absolute paths when base_path is provided#8322
vladzabolotnyi merged 13 commits into
masterfrom
fix/TT-17508/add-base-path-restrictions

Conversation

@vladzabolotnyi

@vladzabolotnyi vladzabolotnyi commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Description

Ticket: Link

file:// KV references are now restricted to relative paths confined within a configured
kv.file.base_path
, and base_path is required:

  • base_path not setfile:// references are disabled; every key (absolute or
    relative) is rejected and no file contents are read.
  • base_path set → only relative keys resolve; they are joined to base_path and
    confined within it. Absolute paths and .. traversal are rejected.

base_path is the security boundary that pins all file:// lookups to a single directory.
Previously it was optional and absolute keys bypassed it entirely, so the boundary wasn't
actually enforced. This change makes it mandatory and authoritative: no base_path, no
file://; with base_path, only relative, confined paths are allowed.

The file:// KV option is not yet released, so making base_path mandatory carries no
backward-compatibility impact.

Related Issue

https://tyktech.atlassian.net/browse/TT-17508

Motivation and Context

The file:// KV option allowed absolute paths to bypass base_path. In a multi-tenant
setup, an untrusted API designer could inject file:///etc/passwd into an API definition
(e.g. a mock body or custom header) and have the gateway read that file and inject its
contents back — arbitrary file disclosure.

The root cause was that ResolveFileKV treated absolute keys as an escape hatch and left
boundary enforcement to each caller. One caller (mw_url_rewrite) did it; two others
(replaceFileSecrets, kvStore) did not — so the boundary was enforced by convention and
silently missed in two places.

The fix moves enforcement into a single chokepoint (ResolveFileKV) and goes further than
just rejecting absolute keys: it requires base_path to be configured for file:// to work
at all. With the policy centralized, all three callers are covered automatically and the
boundary can no longer be silently bypassed.

How This Has Been Tested

  • Unit tests
  • Manual testing

Demo

When base_path is not set, the file:// references are restricted; absolute paths are restricted no matter what

Screen.Recording.2026-06-18.at.13.31.09.mov

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Refactoring or add test (improvements in base code or adds test coverage to functionality)

Checklist

  • I ensured that the documentation is up to date
  • I explained why this PR updates go.mod in detail with reasoning why it's required
  • I would like a code coverage CI quality gate exception and have explained why

@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

🎯 Recommended Merge Targets

Based on JIRA ticket TT-17508: [security] Arbitrary File Read vulnerability in file:// reference

Fix Version: Tyk 5.14.0

⚠️ Warning: Expected release branches not found in repository

Required:

  • master - No matching release branches found. Fix will be included in future releases.

📋 Workflow

  1. Merge this PR to master first

@probelabs

probelabs Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

This PR addresses a critical security vulnerability (TT-17508) by enforcing that file:// key-value (KV) references are restricted to a mandatory, pre-configured base directory. Previously, absolute paths could bypass the optional base_path, creating an arbitrary file read vulnerability that could allow an untrusted API designer to access sensitive files on the gateway's filesystem (e.g., file:///etc/passwd).

The core of the fix is centralizing all path validation logic into the gateway.ResolveFileKV function. This function now implements a "secure-by-default" policy:

  1. kv.file.base_path is now mandatory. If it is not set, all file:// references are rejected.
  2. When base_path is set, it must be an absolute path.
  3. All keys used in file:// references must be relative paths; absolute paths are strictly rejected.
  4. The resolved path is checked to ensure it remains confined within the base_path, preventing path traversal attacks (e.g., ../../..) and symlink escapes.

This change removes redundant and incomplete validation logic from callers like the URL Rewrite middleware, ensuring the security policy is applied consistently across all features that use the file KV store.

Files Changed Analysis

  • gateway/kv_file.go: This file contains the primary logic change. The ResolveFileKV function was refactored to use new helper functions (resolveKeyPath, confined) that enforce the mandatory base_path and reject absolute or traversing paths. It also includes protection against symlink escape vulnerabilities.
  • gateway/kv_file_test.go: The test suite was significantly expanded to cover the new security policies, including new tests for absolute path rejection, mandatory base_path enforcement, and the behavior of the confined path checker.
  • gateway/mw_url_rewrite.go: The middleware was simplified by removing its local (and incomplete) absolute path check, now relying entirely on the centralized and hardened ResolveFileKV function.
  • config/config.go: The documentation for FileConfig.BasePath was updated to reflect its new role as a mandatory security boundary.
  • gateway/api_definition_test.go, gateway/mw_url_rewrite_test.go, gateway/server_test.go: These test files were updated to align with the new, stricter security constraints, ensuring that API loading, variable substitution, and initial configuration loading all respect the base_path boundary.

Architecture & Impact Assessment

  • What this PR accomplishes: It patches a critical arbitrary file disclosure vulnerability by making kv.file.base_path a mandatory and strictly enforced security boundary for all file:// operations. It shifts the feature from being insecure by default to secure by default.
  • Key technical changes introduced: The main architectural change is the centralization of the security policy into a single choke-point (ResolveFileKV). This eliminates the possibility of callers forgetting to implement security checks and ensures consistent enforcement.
  • Affected system components: This change impacts all features that utilize the file:// KV provider. This includes:
    • API Definition Loading: Resolving secrets (e.g., JWTSource) from files.
    • URL Rewrite Middleware: Substituting values from files using $secret_file.* variables.
    • Gateway Configuration: Loading initial configuration values like mTLS certificates from files.
    • General KV Store Access: Any direct use of kvStore("file://...").

System Flow Diagram

graph TD
    subgraph Callers
        A[API Definition Loading]
        B[URL Rewrite Middleware]
        C[Config Loading]
    end

    subgraph "Centralized KV Logic (kv_file.go)"
        D{ResolveFileKV}
        E[resolveKeyPath]
        F[confined]
    end

    subgraph Configuration
        G["kv.file.base_path"]
    end

    A -- "file://key" --> D
    B -- "file://key" --> D
    C -- "file://key" --> D

    G --|Informs policy|--> E

    D --|Delegates validation|--> E
    E --|Boundary check|--> F

    subgraph "Policy Enforcement in resolveKeyPath"
        H{"base_path set?"}
        I{"Path absolute?"}
        J{"Path confined?"}
        K[Reject Request]
        L["Allow and Read File"]
    end

    E --> H
    H -- No --> K
    H -- Yes --> I
    I -- Yes --> K
    I -- No --> J
    J -- No --> K
    J -- Yes --> L
Loading

Scope Discovery & Context Expansion

The changes are correctly focused on the file-based KV store implementation in gateway/kv_file.go. By centralizing the security checks in ResolveFileKV, the fix effectively protects all call sites without requiring changes to each one. The primary consumers impacted are:

  1. replaceFileSecrets (in gateway/api_loader.go): Processes secrets in API definitions during loading. It relies on kvStore, which now benefits from the centralized validation.
  2. replaceVariables (in gateway/mw_url_rewrite.go): Handles $secret_file.* substitutions at runtime and is now secure.
  3. resolveFileSecretsInConfig (in gateway/server.go): Loads configuration values at startup, ensuring the gateway itself is not configured with insecure paths.

By fixing the vulnerability at its source, this PR provides a robust and comprehensive solution that protects all current and future uses of the file:// KV store.

Metadata
  • Review Effort: 3 / 5
  • Primary Label: bug

Powered by Visor from Probelabs

Last updated: 2026-06-18T13:53:41.087Z | Triggered by: pr_updated | Commit: 62bc30c

💡 TIP: You can chat with Visor using /visor ask <your question>

@probelabs

probelabs Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

✅ Security Check Passed

No security issues found – changes LGTM.

✅ Architecture Check Passed

No architecture issues found – changes LGTM.

Performance Issues (1)

Severity Location Issue
🟡 Warning gateway/kv_file.go:45-49
The function `ResolveFileKV` resolves the canonical path of `basePath` using `filepath.EvalSymlinks` on every call. This can lead to redundant syscalls when the function is invoked multiple times in a loop with the same `basePath`, such as in the URL rewrite middleware when processing multiple `$secret_file` variables in a single request. Each variable would trigger a separate, identical syscall to resolve the base path.
💡 SuggestionConsider caching the resolved canonical base path to avoid repeated syscalls. A possible approach is to resolve the base path once outside the loop in performance-critical callers like 'replaceVariables' and pass the canonical path to the resolving logic. This might involve creating a new internal helper function to avoid breaking the signature of the exported `ResolveFileKV` function.

✅ Quality Check Passed

No quality issues found – changes LGTM.


Powered by Visor from Probelabs

Last updated: 2026-06-18T13:53:19.366Z | Triggered by: pr_updated | Commit: 62bc30c

💡 TIP: You can chat with Visor using /visor ask <your question>

@vladzabolotnyi
vladzabolotnyi enabled auto-merge (squash) June 18, 2026 13:26
@sentinelone-cnapp-eu1

Copy link
Copy Markdown

SentinelOne CNS Hardcoded Secret Detector
✅ Congratulations, your code is safe

SentinelOne CNS is a cloud-agnostic, agentless CSPM & CWPP solution that continuously detects and prevents vulnerabilities that have the highest probability of being exploited in Azure, AWS, Google Cloud, and Kubernetes.

@github-actions

Copy link
Copy Markdown
Contributor

🚨 Jira Linter Failed

Commit: 62bc30c
Failed at: 2026-06-18 13:51:14 UTC

The Jira linter failed to validate your PR. Please check the error details below:

🔍 Click to view error details
failed to get Jira issue: failed to fetch Jira issue TT-17508: Issue does not exist or you do not have permission to see it.: request failed. Please analyze the request body for more details. Status code: 404

Next Steps

  • Ensure your branch name contains a valid Jira ticket ID (e.g., ABC-123)
  • Verify your PR title matches the branch's Jira ticket ID
  • Check that the Jira ticket exists and is accessible

This comment will be automatically deleted once the linter passes.

@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Passed Quality Gate passed

Issues
0 New issues
0 Accepted issues

Measures
0 Security Hotspots
100.0% Coverage on New Code
0.0% Duplication on New Code

See analysis details on SonarQube Cloud

@vladzabolotnyi
vladzabolotnyi merged commit 2185ff2 into master Jun 18, 2026
54 of 56 checks passed
@vladzabolotnyi
vladzabolotnyi deleted the fix/TT-17508/add-base-path-restrictions branch June 18, 2026 15:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants