Skip to content

feat(loading): sandbox local loading with WithRoot (GHSA-v2xp-g8xf-22pf)#203

Merged
fredbi merged 2 commits into
go-openapi:masterfrom
fredbi:fix/vuln-loading
Jun 1, 2026
Merged

feat(loading): sandbox local loading with WithRoot (GHSA-v2xp-g8xf-22pf)#203
fredbi merged 2 commits into
go-openapi:masterfrom
fredbi:fix/vuln-loading

Conversation

@fredbi

@fredbi fredbi commented Jun 1, 2026

Copy link
Copy Markdown
Member

Allow for optional secure sandboxing of the spec loader when reading local files.

The defaults remain non-secure as it would introduce severe breaking changes downstream. Sandboxing therefore remains opt-in.

LoadFromFileOrHTTP resolved file:// URIs and bare paths straight to os.ReadFile with no confinement, so a caller that forwards untrusted input could read any file the process can access (file:///etc/passwd, absolute paths, etc.). The advised mitigation, WithFS(os.DirFS(dir)), blocks ".." traversal but not symlinks that escape the root.

Add WithRoot(dir): an opt-in, non-breaking option that confines local reads to dir via os.Root. It resolves every requested path relative to dir and rejects absolute paths, ".." traversal, and escaping symlinks -- including the symlink case os.DirFS misses. The root is opened per read and closed (no fd leak); the open error is wrapped with ErrLoader. WithRoot and WithFS are mutually exclusive (last applied wins).

Also fix a latent bug in LoadStrategy: it applied native separators (filepath.FromSlash) to fs-backed loaders, breaking multi-segment paths on Windows for any fs.FS. fs-backed loaders now receive forward slashes on all platforms, preserving embed.FS's existing always-"/" rule; the native path is kept only for the default os.ReadFile loader.

Document the default permissive behavior and steer untrusted-input callers to WithRoot in the package and function godoc.

Change type

Please select: 🆕 New feature or enhancement|🔧 Bug fix'|📃 Documentation update

Short description

Fixes

Full description

Checklist

  • I have signed all my commits with my name and email (see DCO. This does not require a PGP-signed commit
  • I have rebased and squashed my work, so only one commit remains
  • I have added tests to cover my changes.
  • I have properly enriched go doc comments in code.
  • I have properly documented any breaking change.

Allow for optional secure sandboxing of the spec loader when reading
local files.

The defaults remain non-secure as it would introduce severe breaking
changes downstream. Sandboxing therefore remains opt-in.

LoadFromFileOrHTTP resolved file:// URIs and bare paths straight to
os.ReadFile with no confinement, so a caller that forwards untrusted
input could read any file the process can access (file:///etc/passwd,
absolute paths, etc.). The advised mitigation, WithFS(os.DirFS(dir)),
blocks ".." traversal but not symlinks that escape the root.

Add WithRoot(dir): an opt-in, non-breaking option that confines local
reads to dir via os.Root. It resolves every requested path relative to
dir and rejects absolute paths, ".." traversal, and escaping symlinks --
including the symlink case os.DirFS misses. The root is opened per read
and closed (no fd leak); the open error is wrapped with ErrLoader.
WithRoot and WithFS are mutually exclusive (last applied wins).

Also fix a latent bug in LoadStrategy: it applied native separators
(filepath.FromSlash) to fs-backed loaders, breaking multi-segment paths
on Windows for any fs.FS. fs-backed loaders now receive forward slashes
on all platforms, preserving embed.FS's existing always-"/" rule; the
native path is kept only for the default os.ReadFile loader.

Document the default permissive behavior and steer untrusted-input
callers to WithRoot in the package and function godoc.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Frederic BIDON <fredbi@yahoo.com>
@codecov

codecov Bot commented Jun 1, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.53%. Comparing base (2e99502) to head (21f019a).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #203      +/-   ##
==========================================
+ Coverage   92.48%   92.53%   +0.04%     
==========================================
  Files          54       54              
  Lines        2582     2598      +16     
==========================================
+ Hits         2388     2404      +16     
  Misses        148      148              
  Partials       46       46              

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

The remote loader is a thin wrapper over a standard net/http client and,
like http.DefaultClient, follows redirects and applies no destination
filtering. A caller that forwards untrusted URLs can thus trigger
server-side request forgery (internal services, cloud metadata).

Embedding a network policy (IP denylists, allowlists) in a general fetch
utility is the wrong layer and invites false confidence: the existing
WithHTTPClient option already lets a caller install a guarded transport
that filters destinations at dial time, which is the only point that
survives redirects and DNS rebinding. Document the exposure in the
package godoc and add a runnable, self-validating example showing the
WithHTTPClient + net.Dialer.Control recipe.

Separately, fix a latent correctness bug: LoadStrategy routed any path
with a bare "http" prefix to the remote loader, so a local file named
e.g. "httpbin.json" was misrouted, and an uppercase "HTTP://" URL was
sent to the local loader. Require a real, case-insensitive http:// or
https:// scheme instead.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Frederic BIDON <fredbi@yahoo.com>
@fredbi fredbi merged commit eefaba1 into go-openapi:master Jun 1, 2026
19 checks passed
@fredbi fredbi deleted the fix/vuln-loading branch June 1, 2026 10:55
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.

1 participant