Skip to content

fix: resolve TOCTOU symlink vulnerability in FileHandler gc and destroy#10298

Open
gr8man wants to merge 11 commits into
codeigniter4:developfrom
gr8man:fix/filehandler-gc-toctou
Open

fix: resolve TOCTOU symlink vulnerability in FileHandler gc and destroy#10298
gr8man wants to merge 11 commits into
codeigniter4:developfrom
gr8man:fix/filehandler-gc-toctou

Conversation

@gr8man

@gr8man gr8man commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Description
This PR fixes a Time-of-Check to Time-of-Use (TOCTOU) vulnerability within the FileHandler session driver.

Previously, gc() and destroy() relied on is_file() and filemtime(), which automatically follow symbolic links. In a shared hosting environment with a predictable or shared session save path (like /tmp), an attacker could potentially replace their session file with a symlink pointing to another system file. By racing the garbage collector, they could use the unlink() operation as an oracle to infer the modification time (mtime) of arbitrary files on the system, depending on whether their symlink was deleted or not. It also resolves false-positives raised by strict security scanners regarding the lack of is_link checks before unlink.

Changes:

  • Switched to using lstat() in FileHandler::gc() to retrieve file stats without following symbolic links.
  • Added strict is_link() checks before any @unlink() calls in both gc() and destroy() to ensure the handler explicitly ignores symlinks.
  • Implemented FileHandlerTest.php to thoroughly verify that symbolic links are appropriately ignored by the garbage collector and the destruction routine.

Checklist:

  • Secure against symlink race conditions (TOCTOU).
  • Covered by unit tests (tests/system/Session/Handlers/FileHandlerTest.php).
  • Passes PHPStan static analysis and Coding Standards fixers.

@gr8man gr8man force-pushed the fix/filehandler-gc-toctou branch from ea56cf1 to b078a2f Compare June 10, 2026 19:43
michalsn and others added 10 commits June 10, 2026 21:49
…r4#10291)

Updates the requirements on [boundwize/structarmed](https://github.com/boundwize/structarmed) to permit the latest version.

Updates `boundwize/structarmed` to 0.12.5
- [Release notes](https://github.com/boundwize/structarmed/releases)
- [Commits](boundwize/structarmed@0.12.0...0.12.5)

---
updated-dependencies:
- dependency-name: boundwize/structarmed
  dependency-version: 0.12.5
  dependency-type: direct:development
  dependency-group: composer-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…r4#10292)

Updates the requirements on [boundwize/structarmed](https://github.com/boundwize/structarmed) to permit the latest version.

Updates `boundwize/structarmed` to 0.12.6
- [Release notes](https://github.com/boundwize/structarmed/releases)
- [Commits](boundwize/structarmed@0.12.5...0.12.6)

---
updated-dependencies:
- dependency-name: boundwize/structarmed
  dependency-version: 0.12.6
  dependency-type: direct:development
  dependency-group: composer-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [shivammathur/setup-php](https://github.com/shivammathur/setup-php) in `/` from 2.37.1 to 2.37.2.


Updates `shivammathur/setup-php` from 2.37.1 to 2.37.2
- [Release notes](https://github.com/shivammathur/setup-php/releases)
- [Commits](shivammathur/setup-php@7c071df...f3e473d)

---
updated-dependencies:
- dependency-name: shivammathur/setup-php
  dependency-version: 2.37.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github_actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
@gr8man gr8man force-pushed the fix/filehandler-gc-toctou branch from 24bc734 to 92cbb2d Compare June 10, 2026 19:50
@github-actions github-actions Bot added github_actions Pull requests that update Github_actions code and removed github_actions Pull requests that update Github_actions code labels Jun 10, 2026
@gr8man gr8man force-pushed the fix/filehandler-gc-toctou branch from 6670366 to 92cbb2d Compare June 10, 2026 20:10
@github-actions github-actions Bot added the github_actions Pull requests that update Github_actions code label Jun 10, 2026
@michalsn

Copy link
Copy Markdown
Member

Rebase went wrong, and PR has commits that were already merged.

@michalsn michalsn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR fixes a Time-of-Check to Time-of-Use (TOCTOU) vulnerability within the FileHandler session driver.

I don't think this is really a TOCTOU fix. The patched code still performs several non-atomic check-then-use operations: lstat(), is_link(), is_file(), then @unlink(). The symlink-following behavior is from filemtime(), not from unlink(): unlink() deletes the symlink entry, not the file it points to.

In a shared hosting environment with a predictable or shared session save path (like /tmp)...

The described scenario depends on using a shared session save path such as /tmp, but the user guide explicitly warns not to use publicly readable or shared directories for FileHandler sessions and says only our app should have access to the savePath. The default savePath is WRITEPATH . 'session'.

an attacker could potentially replace their session file with a symlink pointing to another system file.

If we assume symlink planting in the session save path is something we want to protect against, then read() and write() also need to be considered, because they use fopen(), touch(), and ftruncate() on the same path and still follow symlinks.

It also resolves false-positives raised by strict security scanners regarding the lack of is_link checks before unlink.

I don't think scanner false positives alone are enough reason to change runtime behavior here.

Overall, IMO these changes are not necessary.

Comment on lines +295 to +297
$stat = @lstat($filePath);

if ($stat === false || is_link($filePath) || ! is_file($filePath) || $stat['mtime'] > $ts) {

@michalsn michalsn Jun 11, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once is_link() filters links out, filemtime() on a non-link equals the stat['mtime'] - the whole lstat() call is unnecessary.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

github_actions Pull requests that update Github_actions code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants