)]}'
{
  "commit": "82215dc6c01ed6efb6f4f236cd5c87ceb6dc318a",
  "tree": "84d28fbb3abe20ffb6dc31026a85c49b43beba90",
  "parents": [
    "183e2012512cbb7bd7997f0481c134c658d845ed"
  ],
  "author": {
    "name": "Damien Neil",
    "email": "dneil@google.com",
    "time": "Tue May 26 13:59:05 2026 -0700"
  },
  "committer": {
    "name": "Gopher Robot",
    "email": "gobot@golang.org",
    "time": "Tue Jul 07 14:11:06 2026 -0700"
  },
  "message": "os: properly handle trailing slashes in paths in Root\n\nThis change fixes a significant mechanism by which\noperations in a Root can escape the root.\n\nThe implementation of Root on platforms supporting the openat\nfamily of functions assumed that openat(parent, \"f/\", O_NOFOLLOW)\nwould not resolve symlinks in \"f\". This is not correct; the\ntrailing slash causes f to be resolved.\n\nThis permits Root operations to escape when the target filename\nends in a slash and the target is a symlink to a directory outside the\nroot. This does not permit directly accessing non-directory files\noutside a root, since the trailing slash adds a requirement that the\ntarget be a directory. However, under some circumstances an attacker\nmight exploit this flaw to access non-directory files outside\na root, for example by first renaming a directory outside the root\nto a location within it and then accessing files within that directory.\n\nThis change adjusts Root\u0027s handling of slash-terminated paths.\nTrailing slashes are removed from the path at the start of an\noperation, and the presence of slashes is tracked as a boolean.\nSlashes are never reattached to a path component.\n\nIn addition, the doInRoot helper function now automatically\nhandles trailing slashes in a POSIX-compatible fashion.\nWhen a path ends in one or more slashes:\n  - symlinks in the final component are resolved; and\n  - the final path component after symlink resolutions\n    must reference a directory.\n\nThis change also adds a new sets of tests to exercise Root\u0027s\nbehavior in a wider variety of circumstances. These tests\nrun through a matrix of file configurations, such as:\n  - path \"target\", a regular file\n  - path \"dir/../target\", a directory\n  - path \"target/\", a symlink to \"dir/../target/\", which does not exist\n  - etc.\n\nThese tests execute Root operations and the corresponding unrooted\noperation, validate specific expected results for some configurations,\nand verify that the rooted and unrooted versions of the operation\nproduce the same result.\n\nThanks to Mundur (https://github.com/M0nd0R) for reporting this issue.\n\nFixes #79005\nFixes CVE-2026-39822\n\nChange-Id: I34072ab63f2367baf236592f11143f4e6a6a6964\nReviewed-on: https://go-internal-review.googlesource.com/c/go/+/4740\nReviewed-by: Neal Patel \u003cnealpatel@google.com\u003e\nReviewed-by: Roland Shoemaker \u003cbracewell@google.com\u003e\nReviewed-on: https://go-review.googlesource.com/c/go/+/797880\nAuto-Submit: David Chase \u003cdrchase@google.com\u003e\nReviewed-by: Dmitri Shuralyov \u003cdmitshur@golang.org\u003e\nReviewed-by: Dmitri Shuralyov \u003cdmitshur@google.com\u003e\nLUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com \u003cgolang-scoped@luci-project-accounts.iam.gserviceaccount.com\u003e\n",
  "tree_diff": [
    {
      "type": "modify",
      "old_id": "bea38c905a673fca91e6efc4285cdbc1c9e8d74d",
      "old_mode": 33188,
      "old_path": "src/os/export_test.go",
      "new_id": "01bdf8cea0538f9b9655533693656c875ea8dc37",
      "new_mode": 33188,
      "new_path": "src/os/export_test.go"
    },
    {
      "type": "modify",
      "old_id": "d759727ce7a89bce79d67979a51e46c2c7dc8bf3",
      "old_mode": 33188,
      "old_path": "src/os/root.go",
      "new_id": "80e655e4fbdac22c4cc2df31044cd9e4e594a4cb",
      "new_mode": 33188,
      "new_path": "src/os/root.go"
    },
    {
      "type": "modify",
      "old_id": "56a37dafe1626e5125c69f4d8c7bf9310bd8ffbe",
      "old_mode": 33188,
      "old_path": "src/os/root_js.go",
      "new_id": "b201f1c406c5688154a236a516777a470f1d0768",
      "new_mode": 33188,
      "new_path": "src/os/root_js.go"
    },
    {
      "type": "modify",
      "old_id": "59f1abe91b0b2e3dfa4fedab55d355a3ad34506b",
      "old_mode": 33188,
      "old_path": "src/os/root_noopenat.go",
      "new_id": "228b580db41be9b4d73be9f2845a1cb4bb5941dc",
      "new_mode": 33188,
      "new_path": "src/os/root_noopenat.go"
    },
    {
      "type": "modify",
      "old_id": "83bde5ef14160d08763b017283351251e355b5f1",
      "old_mode": 33188,
      "old_path": "src/os/root_openat.go",
      "new_id": "d7c9334ac1919c9b0df045565ac72dbf0f390bd8",
      "new_mode": 33188,
      "new_path": "src/os/root_openat.go"
    },
    {
      "type": "modify",
      "old_id": "2e74ebe3b877431fb456a4b4bce1ab551bff3f13",
      "old_mode": 33188,
      "old_path": "src/os/root_test.go",
      "new_id": "5e0acf94f6adbbde235422738d0fa9a634a78a7e",
      "new_mode": 33188,
      "new_path": "src/os/root_test.go"
    },
    {
      "type": "modify",
      "old_id": "885a8353ebc455beb2854810a633b04bcbcb47a1",
      "old_mode": 33188,
      "old_path": "src/os/root_unix.go",
      "new_id": "e88058715387b3984c9024f90a81ac7380b02e32",
      "new_mode": 33188,
      "new_path": "src/os/root_unix.go"
    },
    {
      "type": "modify",
      "old_id": "b4b37c2be9dea20c2db9bb60f063d09b7c625561",
      "old_mode": 33188,
      "old_path": "src/os/root_unix_test.go",
      "new_id": "9790a13164caf7486f817431223e54aae23aaf1c",
      "new_mode": 33188,
      "new_path": "src/os/root_unix_test.go"
    },
    {
      "type": "modify",
      "old_id": "362963daa7ce02f2f2bdf1ccf8c76bc8a2422288",
      "old_mode": 33188,
      "old_path": "src/os/root_windows.go",
      "new_id": "e03e5d4c2cc73bb52bbf74227b193b96ebdef531",
      "new_mode": 33188,
      "new_path": "src/os/root_windows.go"
    }
  ]
}
