Skip to content

Prevent secrets from being fetched as remote relative paths - #977

Merged
mauvilsa merged 2 commits into
mainfrom
fix-relative-paths-secrets
Sep 16, 2026
Merged

mauvilsa merged 2 commits into
mainfrom
fix-relative-paths-secrets

Conversation

@mauvilsa

Copy link
Copy Markdown
Owner

What does this PR do?

Checking whether a value is an existing path means accessing it. When a config is read from a URL or through fsspec, relative paths are resolved against the remote parent of that config, so a union type like Path_fsr | SecretStr sent the secret itself to the remote server as a request for <remote parent>/<secret>, leaking it. The leak only needed the path subtype to be tried before the secret subtype, which is what happens with an inline secret in a remote config.

Unions that include a secret type now resolve relative paths locally only. Values with an explicit scheme are still fetched, so an intentional s3://bucket/password.txt keeps working, and local relative paths are unaffected. Types without a secret keep the previous behavior.

Changes:

  • typing.py: new is_secret_type helper, true for jsonargparse.typing.SecretStr and pydantic.SecretStr.
  • _paths.py: new disable_remote_relative_paths context manager, backed by a context variable that Path.__init__ checks before resolving a relative path against a remote parent. When it skips one, it debug logs the remote parent and the reason, never the path, since the path could be the secret.
  • _typehints.py: the Union branch of adapt_typehints wraps the loop over subtypes in that context manager when any subtype is a secret type. Wrapping the whole loop also covers unions nested inside the subtypes.

The changelog entry is under Fixed, the documentation notes the behavior with the secret types and adds a warning about it to the "Parsing URLs" section.

Before submitting

  • Did you read the contributing guideline?
  • If you used a coding agent, did you fully understand and validate all generated code and ensure it follows the contributing guidelines?
  • Did you update the documentation? (readme and public docstrings)
  • Did you write unit tests such that there is 100% coverage on related code? (required for bug fixes and new features)
  • Did you verify that new and existing tests pass locally?
  • If this is a bug fix, did you verify that the tests fail without the code fix?
  • Did you make sure that all changes preserve backward compatibility?
  • Did you update the CHANGELOG including a pull request link? (not for typos, docs, test updates, or minor internal changes/refactors)

@mauvilsa mauvilsa added the bug Something isn't working label Sep 16, 2026
@codecov

codecov Bot commented Sep 16, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (d52ea14) to head (734ed20).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff            @@
##              main      #977   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           27        27           
  Lines         9043      9069   +26     
=========================================
+ Hits          9043      9069   +26     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

@greptile-apps

greptile-apps Bot commented Sep 16, 2026

Copy link
Copy Markdown

Greptile Summary

This PR prevents values accepted by secret-containing unions from being probed as relative paths against a remote configuration parent.

  • Adds context-scoped suppression of remote-relative path resolution.
  • Detects direct jsonargparse and pydantic SecretStr union members.
  • Preserves explicitly schemed remote paths and local relative paths.
  • Adds regression coverage and documents the new behavior.
  • Two disclosure paths remain: wrapped secret hints bypass detection, and the new diagnostic can log credentials from the remote parent URL.

Confidence Score: 1/5

The PR is not safe to merge until wrapped secret hints cannot trigger remote probes and remote-parent credentials are redacted from the new diagnostic.

Direct SecretStr unions are protected, but Annotated[SecretStr, ...] bypasses the detection gate and the skip diagnostic newly exposes unredacted credential-bearing remote URLs.

Files Needing Attention: jsonargparse/_typehints.py, jsonargparse/_paths.py, jsonargparse/typing.py

Security Review

Two credential-disclosure issues remain. Annotated[SecretStr, ...] is not recognized before path probing, allowing the original remote-request leak to persist for a supported wrapper. Additionally, the new debug diagnostic logs remote-parent URLs without removing embedded credentials or token-bearing query data.

Important Files Changed
Filename Overview
jsonargparse/_paths.py Adds context-scoped remote-relative suppression, but the associated diagnostic emits unredacted remote-parent URLs.
jsonargparse/_typehints.py Enables suppression for direct secret union members, but checks unnormalized members and misses wrapped secret hints.
jsonargparse/typing.py Adds narrowly defined secret-type recognition based on exact identity or pydantic module/name.
jsonargparse_tests/test_paths.py Thoroughly covers direct secret unions and path-resolution behavior but omits wrapped secret hints and credential-bearing parent URLs.
jsonargparse_tests/test_pydantic.py Adds focused coverage for a direct pydantic SecretStr union member.
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Value from remote config] --> B{Union directly contains recognized SecretStr?}
  B -->|Yes| C[Disable remote-relative resolution]
  B -->|No, including Annotated wrapper| D[Try path subtype normally]
  C --> E{Value has explicit scheme?}
  E -->|Yes| F[Fetch explicit remote path]
  E -->|No| G[Try local relative path]
  G -->|Path fails| H[Adapt as SecretStr]
  D --> I[Probe remote parent plus value]
  I --> J[Potential secret disclosure]
  C --> K[Log skipped remote parent]
  K --> L[Potential URL credential disclosure]
Loading

Reviews (1): Last reviewed commit: "Prevent secrets from being fetched as re..." | Re-trigger Greptile

Comment thread jsonargparse/_typehints.py
Comment thread jsonargparse/_paths.py
@sonarqubecloud

Copy link
Copy Markdown

@mauvilsa
mauvilsa merged commit cc43ecd into main Sep 16, 2026
31 of 32 checks passed
@mauvilsa
mauvilsa deleted the fix-relative-paths-secrets branch September 16, 2026 19:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant