Skip to content

Commit a80c301

Browse files
1 parent b8daa6e commit a80c301

5 files changed

Lines changed: 321 additions & 0 deletions

File tree

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-9f3r-2vgw-m8xp",
4+
"modified": "2026-03-16T20:45:12Z",
5+
"published": "2026-03-16T20:45:12Z",
6+
"aliases": [
7+
"CVE-2026-32758"
8+
],
9+
"summary": "File Browser has an Access Rule Bypass via Path Traversal in Copy/Rename Destination Parameter",
10+
"details": "## Description\n\nThe `resourcePatchHandler` in `http/resource.go` validates the destination path against configured access rules before the path is cleaned/normalized. The rules engine (`rules/rules.go`) uses literal string prefix matching (`strings.HasPrefix`) or regex matching against the raw path. The actual file operation (`fileutils.Copy`, `patchAction`) subsequently calls `path.Clean()` which resolves `..` sequences, producing a different effective path than the one validated.\n\nThis allows an authenticated user with Create or Rename permissions to bypass administrator-configured deny rules by including `..` (dot-dot) path traversal sequences in the `destination` query parameter of a PATCH request.\n\n## Steps to Reproduce\n\n### 1. Verify the rule works normally\n\n```bash\n# This should return 403 Forbidden\ncurl -X PATCH \\\n -H \"X-Auth: <alice_jwt>\" \\\n \"http://host/api/resources/public/test.txt?action=copy&destination=%2Frestricted%2Fcopied.txt\"\n```\n\n### 2. Exploit the bypass\n\n```bash\n# This should succeed despite the deny rule\ncurl -X PATCH \\\n -H \"X-Auth: <alice_jwt>\" \\\n \"http://host/api/resources/public/test.txt?action=copy&destination=%2Fpublic%2F..%2Frestricted%2Fcopied.txt\"\n```\n\n### 3. Result\n\nThe file `test.txt` is copied to `/restricted/copied.txt` despite the deny rule for `/restricted/`.\n\n## Root Cause Analysis\n\nIn `http/resource.go:209-257`:\n\n```go\ndst := r.URL.Query().Get(\"destination\") // line 212\ndst, err := url.QueryUnescape(dst) // line 214 — dst contains \"..\"\nif !d.Check(src) || !d.Check(dst) { // line 215 — CHECK ON UNCLEANED PATH\n return http.StatusForbidden, nil\n}\n```\n\nIn `rules/rules.go:29-35`:\n\n```go\nfunc (r *Rule) Matches(path string) bool {\n if r.Regex {\n return r.Regexp.MatchString(path) // regex on literal path\n }\n return strings.HasPrefix(path, r.Path) // prefix on literal path\n}\n```\n\nIn `fileutils/copy.go:12-17`:\n\n```go\nfunc Copy(afs afero.Fs, src, dst string, ...) error {\n if dst = path.Clean(\"/\" + dst); dst == \"\" { // CLEANING HAPPENS HERE, AFTER CHECK\n return os.ErrNotExist\n }\n```\n\nThe rules check sees `/public/../restricted/copied.txt` (no match for `/restricted/` prefix).\nThe file operation resolves it to `/restricted/copied.txt` (within the restricted path).\n\n## Secondary Issue\n\nIn the same handler, the error from `url.QueryUnescape` is checked after `d.Check()` runs (lines 214-220), meaning the rules check executes on a potentially malformed string if unescaping fails.\n\n## Impact\n\nAn authenticated user with Copy (Create) or Rename permission can write or move files into any path within their scope that is protected by deny rules. This bypasses both:\n\n- Prefix-based rules: `strings.HasPrefix` on uncleaned path misses the match\n- Regex-based rules: Standard patterns like `^/restricted/.*` fail on uncleaned path\n\nCannot be used to:\n\n- Escape the user's BasePathFs scope (afero prevents this)\n- Read from restricted paths (GET handler uses cleaned `r.URL.Path`)\n\n## Suggested Fix\n\nClean the destination path before the rules check:\n\n```go\ndst, err := url.QueryUnescape(dst)\nif err != nil {\n return errToStatus(err), err\n}\ndst = path.Clean(\"/\" + dst)\nsrc = path.Clean(\"/\" + src)\nif !d.Check(src) || !d.Check(dst) {\n return http.StatusForbidden, nil\n}\nif dst == \"/\" || src == \"/\" {\n return http.StatusForbidden, nil\n}\n```",
11+
"severity": [
12+
{
13+
"type": "CVSS_V3",
14+
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N"
15+
}
16+
],
17+
"affected": [
18+
{
19+
"package": {
20+
"ecosystem": "Go",
21+
"name": "github.com/filebrowser/filebrowser/v2"
22+
},
23+
"ranges": [
24+
{
25+
"type": "ECOSYSTEM",
26+
"events": [
27+
{
28+
"introduced": "0"
29+
},
30+
{
31+
"fixed": "2.62.0"
32+
}
33+
]
34+
}
35+
],
36+
"database_specific": {
37+
"last_known_affected_version_range": "<= 2.61.2"
38+
}
39+
}
40+
],
41+
"references": [
42+
{
43+
"type": "WEB",
44+
"url": "https://github.com/filebrowser/filebrowser/security/advisories/GHSA-9f3r-2vgw-m8xp"
45+
},
46+
{
47+
"type": "PACKAGE",
48+
"url": "https://github.com/filebrowser/filebrowser"
49+
}
50+
],
51+
"database_specific": {
52+
"cwe_ids": [
53+
"CWE-22",
54+
"CWE-863"
55+
],
56+
"severity": "MODERATE",
57+
"github_reviewed": true,
58+
"github_reviewed_at": "2026-03-16T20:45:12Z",
59+
"nvd_published_at": null
60+
}
61+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-f7cq-gvh6-qr25",
4+
"modified": "2026-03-16T20:46:48Z",
5+
"published": "2026-03-16T20:46:48Z",
6+
"aliases": [],
7+
"summary": "Monitoring is vulnerable to Archive Slip due to missing checks in sanitization",
8+
"details": "The `sanitizeArchivePath` function in `pkg/extract/extract.go` (lines 248–254) is vulnerable to a path traversal bypass due to a missing trailing path separator in the `strings.HasPrefix` check. A crafted tar archive can write files outside the intended destination directory when using the `extractor` CLI tool or the `extract.DumpOTelCollector` library function.\n\n## Vulnerable Code\n\nFile: `pkg/extract/extract.go`, lines 248–254\n\n```go\nfunc sanitizeArchivePath(d, t string) (v string, err error) {\n v = filepath.Join(d, t)\n if strings.HasPrefix(v, filepath.Clean(d)) { // ← missing trailing separator\n return v, nil\n }\n return \"\", fmt.Errorf(\"filepath is tainted: %s\", t)\n}\n```\n\nThe function is called at line 219 inside `untar`, which is invoked by `copyFromPod` (line 205) during the Cold Extract data dump workflow.\n\n## Root Cause\n\n`strings.HasPrefix(v, filepath.Clean(d))` does not append a trailing `/` to the directory prefix, causing a **directory name prefix collision**. If the destination is `/home/user/extract-output` and a tar entry is named `../extract-outputevil/pwned`, the joined path `/home/user/extract-outputevil/pwned` passes the prefix check — it starts with `/home/user/extract-output` — even though it is entirely outside the intended directory.\n\n## Steps to Reproduce\n\n1. **Deploy the monitoring stack** with `ColdExtract: true`. The OTEL Collector begins writing signal data (`otel_traces`, `otel_metrics`, `otel_logs`) to the shared PVC.\n\n2. **Place the PoC tar on the PVC.** Any pod with write access to the `ReadWriteMany` PVC (or the compromised OTEL Collector itself) copies a `poc-path-traversal.tar` into the `/data/collector` mount path. The archive contains three real-looking OTLP telemetry files alongside two crafted entries with path-traversal names.\n\n3. **Run the extractor against the namespace:**\n\n ```\n extractor \\\n --namespace monitoring \\\n --pvc-name <signals-pvc-name> \\\n --directory /home/user/extract-output\n ```\n\n4. **Observe the bypass.** `untar` processes the tar stream. For the malicious entries:\n\n ```\n // entry name: ../extract-outputevil/poc-proof.txt\n filepath.Join(\"/home/user/extract-output\", \"../extract-outputevil/poc-proof.txt\")\n => \"/home/user/extract-outputevil/poc-proof.txt\"\n\n strings.HasPrefix(\"/home/user/extract-outputevil/poc-proof.txt\",\n \"/home/user/extract-output\")\n => true // BUG: prefix collision; file lands OUTSIDE target dir\n ```\n\n Both malicious entries are written outside `/home/user/extract-output/`. The three legitimate OTLP files land correctly inside it.\n\n## Impact\n\nSuccessful exploitation gives an attacker arbitrary file write on the machine running the extractor. Real-world primitives include:\n\n- Overwriting `~/.bashrc` / `~/.zshrc` / `~/.profile` for RCE on next shell login\n- Appending to `~/.ssh/authorized_keys` for persistent SSH backdoor\n- Dropping a malicious entry into `~/.kube/config` to hijack cluster access\n- Writing crontab entries for persistent scheduled execution\n\nThe attack surface is widened by the default `ReadWriteMany` PVC access mode, which means any pod in the cluster with the PVC mounted can inject the payload — not just the OTEL Collector itself.",
9+
"severity": [
10+
{
11+
"type": "CVSS_V4",
12+
"score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:H/VA:H/SC:N/SI:L/SA:L"
13+
}
14+
],
15+
"affected": [
16+
{
17+
"package": {
18+
"ecosystem": "Go",
19+
"name": "github.com/ctfer-io/monitoring"
20+
},
21+
"ranges": [
22+
{
23+
"type": "ECOSYSTEM",
24+
"events": [
25+
{
26+
"introduced": "0"
27+
},
28+
{
29+
"fixed": "0.2.2"
30+
}
31+
]
32+
}
33+
]
34+
}
35+
],
36+
"references": [
37+
{
38+
"type": "WEB",
39+
"url": "https://github.com/ctfer-io/monitoring/security/advisories/GHSA-f7cq-gvh6-qr25"
40+
},
41+
{
42+
"type": "WEB",
43+
"url": "https://github.com/ctfer-io/monitoring/commit/269dba165aa42210352628c0db6756f3b8fd3c8a"
44+
},
45+
{
46+
"type": "PACKAGE",
47+
"url": "https://github.com/ctfer-io/monitoring"
48+
}
49+
],
50+
"database_specific": {
51+
"cwe_ids": [
52+
"CWE-22"
53+
],
54+
"severity": "HIGH",
55+
"github_reviewed": true,
56+
"github_reviewed_at": "2026-03-16T20:46:48Z",
57+
"nvd_published_at": null
58+
}
59+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-fgm3-q9r5-43v9",
4+
"modified": "2026-03-16T20:45:59Z",
5+
"published": "2026-03-16T20:45:59Z",
6+
"aliases": [
7+
"CVE-2026-32737"
8+
],
9+
"summary": "Romeo's invalid NetworkPolicy enables a malicious actor to pivot into another namespace ",
10+
"details": "### Impact\n\nDue to a mis-written NetworkPolicy, a malicious actor can pivot from the \"hardened\" namespace to any Pod out of it.\nThis breaks the security-by-default property expected as part of the deployment program, leading to a potential lateral movement.\n\n### Patch\n\nRemoving the `inter-ns` NetworkPolicy patches the vulnerability. If updates are not possible in production environments, we recommend to manually delete it and update as soon as possible.\n\n### Workaround\n\nGiven your context, delete the failing network policy that should be prefixed by `inter-ns-` in the target namespace.",
11+
"severity": [
12+
{
13+
"type": "CVSS_V4",
14+
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:H/SI:H/SA:H"
15+
}
16+
],
17+
"affected": [
18+
{
19+
"package": {
20+
"ecosystem": "Go",
21+
"name": "github.com/ctfer-io/romeo/environment/deploy"
22+
},
23+
"ranges": [
24+
{
25+
"type": "ECOSYSTEM",
26+
"events": [
27+
{
28+
"introduced": "0"
29+
},
30+
{
31+
"fixed": "0.2.1"
32+
}
33+
]
34+
}
35+
]
36+
}
37+
],
38+
"references": [
39+
{
40+
"type": "WEB",
41+
"url": "https://github.com/ctfer-io/romeo/security/advisories/GHSA-fgm3-q9r5-43v9"
42+
},
43+
{
44+
"type": "WEB",
45+
"url": "https://github.com/ctfer-io/romeo/commit/3bb5e9d9ce1199dfbb90fef8ad79ebdeb0bc5e78"
46+
},
47+
{
48+
"type": "PACKAGE",
49+
"url": "https://github.com/ctfer-io/romeo"
50+
}
51+
],
52+
"database_specific": {
53+
"cwe_ids": [
54+
"CWE-284"
55+
],
56+
"severity": "HIGH",
57+
"github_reviewed": true,
58+
"github_reviewed_at": "2026-03-16T20:45:59Z",
59+
"nvd_published_at": null
60+
}
61+
}

0 commit comments

Comments
 (0)