Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .jules/sentinel.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,7 @@ grep -nE "O_NOFOLLOW|O_CLOEXEC|fchmod|withUnsafeFileSystemRepresentation" <candi
**Vulnerability:** Calling `open(2)` with raw Swift `String` paths in `StatusSocket.swift` creates an unsafe filesystem representation.
**Learning:** Passing Swift `String` paths implicitly to C functions can result in memory issues or incorrect path resolution if the string is not null-terminated or is moved in memory.
**Prevention:** Always use `URL(fileURLWithPath:).withUnsafeFileSystemRepresentation` to obtain the correct C-string pointer when bridging file paths to POSIX APIs.
## 2026-05-04 - Fail-Open Security Vulnerability via Ignored fchmodat Error
**Vulnerability:** Ignored the return value of `fchmodat(AT_FDCWD, socketPath, 0o600, AT_SYMLINK_NOFOLLOW)` by using `_ =`.
**Learning:** `fchmodat` on Apple platforms returns `ENOTSUP` (errno 95) if the target is a symlink when the `AT_SYMLINK_NOFOLLOW` flag is used. While this inherently prevents a TOCTOU symlink traversal, the permission change fails completely. Ignoring the error results in a fail-open scenario where the target might maintain insecure permissions (e.g. 0o777).
**Prevention:** Always verify the return value of POSIX C API calls like `fchmodat` and explicitly fail-closed (e.g., throw an error) if the operation fails, rather than silently ignoring the error and proceeding with potentially insecure state.
6 changes: 5 additions & 1 deletion Sources/Cacheout/Headless/StatusSocket.swift
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,11 @@ public final class StatusSocket: @unchecked Sendable {
}
if (sockStat.st_mode & 0o777) != 0o600 {
// umask should have set 0600; defense-in-depth chmod via no-follow.
_ = fchmodat(AT_FDCWD, socketPath, 0o600, AT_SYMLINK_NOFOLLOW)
guard fchmodat(AT_FDCWD, socketPath, 0o600, AT_SYMLINK_NOFOLLOW) == 0 else {
close(fd)
unlink(socketPath)
throw StatusSocketError.bindFailed(errno)
}
}

// Listen
Expand Down
Loading