Skip to content

deps(mcp): update dependency pydantic-settings to v2.14.2 [security]#7841

Open
flagsmith-engineering[bot] wants to merge 1 commit into
mainfrom
renovate/pypi-pydantic-settings-vulnerability
Open

deps(mcp): update dependency pydantic-settings to v2.14.2 [security]#7841
flagsmith-engineering[bot] wants to merge 1 commit into
mainfrom
renovate/pypi-pydantic-settings-vulnerability

Conversation

@flagsmith-engineering

Copy link
Copy Markdown
Contributor

This PR contains the following updates:

Package Change Age Confidence
pydantic-settings (changelog) 2.14.12.14.2 age confidence

pydantic-settings: NestedSecretsSettingsSource follows symlinks outside secrets_dir, enabling local file read and bypassing secrets_dir_max_size

GHSA-4xgf-cpjx-pc3j

More information

Details

Summary

NestedSecretsSettingsSource reads secret values from files in a configured secrets_dir. When secrets_nested_subdir=True, a directory entry inside secrets_dir that is a symbolic link pointing outside secrets_dir is followed, so files outside the configured directory are read into settings values. The same code path bypasses the documented secrets_dir_max_size protection. An attacker or lower-privileged component able to influence entries in the configured secrets directory (for example, a writable or shared secrets mount) can turn this into an unintended local file read into settings and can defeat the advertised loading-size cap. This report does not claim network reachability by itself.

Details

NestedSecretsSettingsSource performed two passes over secrets_dir using two different, inconsistent directory-traversal implementations:

  • The size check in validate_secrets_path() used Path.glob('**/*'), which does not descend into a symbolically-linked directory.
  • The loader in load_secrets() used glob.iglob(f'{path}/**/*', recursive=True) followed by read_text(), which does follow symlinked directories and reads through the link target.

Because the two passes disagreed on symlinks, a symlinked directory inside secrets_dir whose target lives elsewhere was invisible to the size accounting (counted as 0 bytes) while still being fully read by the loader. This produces two distinct problems:

  1. Out-of-tree read (CWE-22 / CWE-59). A symlinked directory (or file) inside secrets_dir that resolves outside it is followed, and the external file's contents are loaded into the corresponding settings field.
  2. secrets_dir_max_size bypass (CWE-400). The size check never sees the out-of-tree content, so the documented size cap is neither respected nor able to reject the oversized external file. A related amplification exists for cyclic in-tree symlinks, which glob.iglob(recursive=True) re-traverses, inflating the size accounting and the number of loaded secrets.
Reproduction

In a clean Linux container, with a secrets_dir containing a symlink secrets/db -> /path/outside and an outside/passwd file of 512 bytes, while secrets_dir_max_size=100:

from pydantic import BaseModel
from pydantic_settings import (
    BaseSettings,
    SettingsConfigDict,
    NestedSecretsSettingsSource,
)

class Db(BaseModel):
    passwd: str | None = None

class Settings(BaseSettings):
    model_config = SettingsConfigDict(
        secrets_dir='secrets',
        secrets_nested_subdir=True,
        secrets_dir_max_size=100,  # outside/passwd is 512 bytes
    )
    db: Db = Db()

    @​classmethod
    def settings_customise_sources(
        cls, settings_cls, init_settings, env_settings, dotenv_settings, file_secret_settings
    ):
        return (NestedSecretsSettingsSource(file_secret_settings),)

On affected versions, Settings().db.passwd is populated with the 512-byte out-of-tree file and no SettingsError is raised, even though the file exceeds secrets_dir_max_size.

Impact

Applications that opt into NestedSecretsSettingsSource with secrets_nested_subdir=True and load secrets from a directory whose entries can be influenced by an attacker or a lower-privileged component (for example, a writable or shared secrets mount, or a secrets directory partially populated from untrusted input) are affected. The impact is:

  • Confidentiality: files outside the configured secrets_dir can be read into settings values (local file read).
  • Integrity / availability of the safeguard: the advertised secrets_dir_max_size cap can be bypassed, and cyclic symlinks can inflate resource usage during loading.

The vulnerability requires the ability to place a symbolic link inside the configured secrets directory; it is not remotely reachable on its own. Applications that do not use NestedSecretsSettingsSource, or that point secrets_dir at a directory fully under the application's control, are not affected.

Mitigation

Upgrade to pydantic-settings 2.14.2, which:

  • walks the secrets directory explicitly and only descends into directories whose resolved path stays within secrets_dir, so symlinked directories pointing outside are never followed;
  • uses a single, cycle-safe iterator for both the size check and the loader, so the size accounting and the loaded set are always consistent and each real directory is visited at most once;
  • skips any file whose resolved path escapes secrets_dir, as defense in depth.

If upgrading is not immediately possible, ensure the configured secrets_dir is fully owned and controlled by the application (no writable or attacker-influenced entries), or avoid secrets_nested_subdir=True.

Severity

  • CVSS Score: 5.3 / 10 (Medium)
  • Vector String: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


Release Notes

pydantic/pydantic-settings (pydantic-settings)

v2.14.2

Compare Source

What's Changed

This is a security patch release.

Security

Fixes GHSA-4xgf-cpjx-pc3j: NestedSecretsSettingsSource with secrets_nested_subdir=True could follow a symbolic link inside secrets_dir pointing outside it, reading out-of-tree files into settings values and bypassing the secrets_dir_max_size cap. Affected versions: >= 2.12.0, < 2.14.2.

Full Changelog: pydantic/pydantic-settings@v2.14.1...v2.14.2


Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR has been generated by Mend Renovate.

@flagsmith-engineering flagsmith-engineering Bot added dependencies Pull requests that update a dependency file mcp labels Jun 20, 2026
@flagsmith-engineering flagsmith-engineering Bot requested a review from a team as a code owner June 20, 2026 04:35
@flagsmith-engineering flagsmith-engineering Bot removed the request for review from a team June 20, 2026 04:35
@flagsmith-engineering flagsmith-engineering Bot added the dependencies Pull requests that update a dependency file label Jun 20, 2026
@flagsmith-engineering flagsmith-engineering Bot requested a review from khvn26 June 20, 2026 04:35
@vercel

vercel Bot commented Jun 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

3 Skipped Deployments
Project Deployment Actions Updated (UTC)
docs Ignored Ignored Preview Jun 20, 2026 4:36am
flagsmith-frontend-preview Ignored Ignored Preview Jun 20, 2026 4:36am
flagsmith-frontend-staging Ignored Ignored Preview Jun 20, 2026 4:36am

Request Review

@github-actions

github-actions Bot commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Playwright Test Results (oss - depot-ubuntu-latest-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  40.7 seconds
commit  c7ec51e
info  🔄 Run: #17692 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-arm-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  37.9 seconds
commit  c7ec51e
info  🔄 Run: #17692 (attempt 1)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file mcp

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant