Skip to main content

Boteraser | Website and Server Security Solutions

🛡️ CVE-2026-55668 — filebrowser

🟡 CVSS 6.3 — Medium ✅ No Known Exploit NVD
6.3
CVSS Score
0 Low4 Medium7 High9 Critical10

Description

File Browser: ScopedFs follows a dangling symlink on write, letting a scoped user create files outside their scope

Summary

ScopedFs confines every File Browser user to a scope directory. Its within() guard is meant to reject any operation that follows a symbolic link out of that scope. When the link target does not exist yet, the guard walks up to the nearest existing ancestor and validates that instead. For a dangling symlink (target does not exist), the nearest existing ancestor is the in-scope directory containing the link, so the guard returns "in scope" and the subsequent os.OpenFile(O_CREATE) follows the link and creates the file at its out-of-scope target.

A post-auth user with Create and Modify permission can write attacker-controlled content to any non-existent path outside their scope that the File Browser process can write to. The precondition is a dangling symlink present inside the user's scope, which is the same out-of-band precondition the rest of ScopedFs is built to defend against.

This is a patch-gap variant of the GHSA-239w-m3h6-ch8v symlink confinement issue, not a resubmission of the already-published vulnerable-version behavior: GHSA-239w-m3h6-ch8v marks <= 2.63.13 vulnerable and 2.63.14 patched, while this proof reproduces on current master / v2.63.15 (be23ab3a15bf957928ecfed88de5ab67850c1b9c). The escaping-symlink-to-an-existing-target case is defended and tested. The dangling case is neither, and the gap is acknowledged in a code comment as "best-effort".

Root cause

files/scoped.go (commit be23ab3). The guard, including the maintainer comment that already flags this exact gap:

```go

// Note: a dangling symlink whose target does not yet exist resolves to its

// containing directory and is therefore allowed; writing through such a link

// could still create a file outside the scope. This is treated as best-effort

// and relies on rejecting existing escaping symlinks, which covers the

// disclosure and overwrite vectors.

func (s *ScopedFs) within(p string) (bool, error) {

root, err := filepath.EvalSymlinks(afero.FullBaseFsPath(s.base, "/"))

if err != nil {

return false, err

}

target := afero.FullBaseFsPath(s.base, p)

resolved, err := filepath.EvalSymlinks(target)

for errors.Is(err, fs.ErrNotExist) {

parent := filepath.Dir(target) // LEXICAL parent of the link path

if parent == target {

break

}

target = parent

resolved, err = filepath.EvalSymlinks(target)

}

if err != nil {

return false, err

}

// ...

return resolved == root || strings.HasPrefix(resolved, prefix), nil

}

```

When p is a symlink whose target does not exist, EvalSymlinks(target) returns fs.ErrNotExist. The loop takes the lexical parent of the link path (filepath.Dir), a real directory inside the scope, and EvalSymlinks of that resolves under the scope root. within() returns true and guard() permits the operation. The write then dereferences the link at the OS layer:

```go

func (s *ScopedFs) OpenFile(name string, flag int, perm os.FileMode) (afero.File, error) {

if err := s.guard(name); err != nil { // returns nil for a dangling escaping symlink

return nil, err

}

return s.base.OpenFile(name, flag, perm) // os.OpenFile(O_CREATE) follows the link

}

```

The assumption that breaks: within() treats "target does not exist" as "brand-new in-scope file" and validates the containing directory. But the path component being created is itself a symlink pointing outside the scope. O_CREATE follows it and creates the file at the link target, not inside the validated directory. The existing-target case is correctly blocked, because the walk-up resolves the link itself to an out-of-scope path. Only the dangling case slips through.

For the layout below:

```text

/tmp/root/scope/escape -> /tmp/root/outside/created-by-http.txt

/tmp/root/outside/ # exists

/tmp/root/outside/created-by-http.txt # does not exist yet

```

EvalSymlinks(/tmp/root/scope/escape) returns not-exist, and the fallback validates /tmp/root/scope. The final OpenFile still follows /tmp/root/scope/escape and creates /tmp/root/outside/created-by-http.txt.

Reachability over HTTP

Endpoint: POST /api/resources/<linkname>?override=true (also PUT, and POST/PATCH /api/tus/...). Verified trace against the audited source:

1. http/resource.go resourcePostHandler requires d.user.Perm.Create (else 403).

2. files.NewFileInfo is called. For a dangling symlink, stat() in files/file.go does LstatIfPossible (sees the symlink, err == nil, IsSymlink = true), then Fs.Stat follows the link and fails with ENOENT, so the code returns the symlink FileInfo with err == nil. The handler therefore enters the "file exists" branch.

3. The branch requires override == "true" and d.user.Perm.Modify, then proceeds.

4. `writeFile(d.user.Fs, r.UR

How this vulnerability can be exploited

This issue can be reached over the network, attack complexity is high, an attacker needs low-level privileges on the target. No user interaction is required. The scope is changed, meaning a successful attack can affect components beyond the vulnerable one. Rated impact: confidentiality none, integrity high, availability none.

CVSS metrics in full

The score comes from this vector: CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:N/I:H/A:N

  • Attack vector: Network — reachable from anywhere that can route to the service.
  • Attack complexity: High — the attacker first has to win a race, learn a secret or otherwise prepare the target.
  • Privileges required: Low — an ordinary user account is enough.
  • User interaction: None — nobody has to be tricked into anything.
  • Scope: Changed — a successful attack reaches components beyond the vulnerable one.
  • Confidentiality impact: None.
  • Integrity impact: High — total loss, or loss the attacker controls.
  • Availability impact: None.

Affected software

CVE-2026-55668 is recorded against 3 packages.

  • github.com/filebrowser/filebrowser
  • github.com/filebrowser/filebrowser/v2
  • unknown

Timeline and source

Published on 22 July 2026. No public exploit is currently recorded for this entry. A vendor advisory or fix has been published. Record sourced from NVD.

References

github.com (Advisory)
nvd.nist.gov (Advisory)
github.com (Fix)
github.com (Web)

Other advisories for this package

github.com/filebrowser/filebrowser has other advisories on record. If you are patching this one, these are worth checking on the same host:

Details

Severity Medium
CVSS Score 6.3
CVSS Vector CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:N/I:H/A:N
CWE N/A
Public Exploit ✅ No
Source NVD
Published 2026-07-22
Updated 2026-08-20
Modified 2026-07-22

Affected Packages

Software From version Fixed in
github.com/filebrowser/filebrowser
github.com/filebrowser/filebrowser/v2
unknown

Similar Threats

Vulnerability Monitoring

Track new vulnerabilities in filebrowser

CVE-2026-55668 is rated CVSS 6.3 Medium. BotEraser monitors your WordPress installation and notifies you when software you use appears in our vulnerability database.

Set Up Free Alerts →

No credit card required  ·  Results in minutes

ⓘ Data Notice: The information presented above has been compiled from publicly available internet sources. Boteraser aggregates this data solely for informational purposes and does not independently classify, evaluate, or endorse any findings about the vulnerabilities listed. The accuracy and completeness of this information is the sole responsibility of the original publishers. Boteraser and its operators accept no liability for any decisions made based on this data.

Browse related advisories

All advisoriesCVECVE 2026