Lucee 7 creating files without "write" permission in Tomcat 11

I’m running into a weird issue after spinning up a new VM. I have another VM where this issue does not exist, but they started from different base ISOs (but same both Oracle Linux Server 9.7)

OS: Oracle Linux Server 9.7 (6.12.0-107.59.3.3.el9uek.x86_64)
Java Version: 25.0.2 (Eclipse Adoptium) 64bit
Tomcat Version: Apache Tomcat/11.0.18
Lucee Version: 7.0.2.62-SNAPSHOT

Whenever Lucee creates a file, the file does not have “write” permissions, only read permissions:

-r--r-----.  1 tomcat webservices unconfined_u:object_r:httpd_sys_content_t:s0 3.0K Jan 30 16:41 test-file.txt

All of the permissions seem like it should be writing files with the write permission. Here’s what I’ve done to verify the permissions:

> systemctl show tomcat | grep UMask
UMask=0022

> grep Umask /proc/$(pgrep -f tomcat)/status
Umask:  0027

> systemctl cat tomcat | grep -E 'User=|Group='
User=tomcat
Group=webservices

> getfacl /var/www/_tmp/
getfacl: Removing leading '/' from absolute path names
# file: var/www/_tmp/
# owner: tomcat
# group: webservices
user::rwx
group::rwx
other::---

The service is setting the umask that I would expect (0027), which should give the owner full permissions.

I’ve tried setting SELinux to permissive mode and temporarily disabling it (setenforce permissive and setenforce 0) to verify that the SELinux rules are not causing an issue and that made no difference.

UPDATE Jan 31, 2026

I have also run the following:

 sudo -u tomcat bash -c 'umask; touch /var/www/_tmp/testfile.txt; ls -l /var/www/_tmp/testfile.txt'

And that generates the file with the correct permissions:

-rw-r--r--.  1 tomcat tomcat      unconfined_u:object_r:httpd_sys_content_t:s0    0 Jan 31 13:14 testfile.txt

Why would Lucee be creating the files with only read permissions with all of the above indicates it the tomcat user should have full permissions?

This is the stack trace produced by a call trying to update a file that was just created:

lucee.runtime.exp.NativeException: /var/www/_tmp/6C2CC5A6-30F1-45D8-98C880CC3C4F1C6B.ini (Permission denied)
   at java.base/java.io.FileOutputStream.open0(Native Method)
   at java.base/java.io.FileOutputStream.open(FileOutputStream.java:255 undefined)
   at java.base/java.io.FileOutputStream.<init>(FileOutputStream.java:210 undefined)
   at lucee.commons.io.res.type.file.FileResource.getOutputStream(FileResource.java:320 undefined)
   at lucee.runtime.functions.file.FileStreamWrapperWrite._getOS(FileStreamWrapperWrite.java:138 undefined)
   at lucee.runtime.functions.file.FileStreamWrapperWrite.write(FileStreamWrapperWrite.java:69 undefined)
   at lucee.runtime.functions.file.FileWrite.call(FileWrite.java:65 undefined)
   at lucee.runtime.functions.file.FileWrite.call(FileWrite.java:39 undefined)

When I use the Java’s File class directly, the file is written with the permissions I’d expect:

new java.io.File("/var/www/_tmp/jvm-test.txt").createNewFile();

This produces:

-r--r-----.  1 tomcat webservices 3.0K Jan 30 16:41 9E552DC3-18CD-4000-B7AB2D78C34F0735.ini
-rw-r-----.  1 tomcat webservices    0 Jan 31 14:19 jvm-test.txt

The 9E552DC3-18CD-4000-B7AB2D78C34F0735.ini file was written with:

fileCopy(source, destination);

The permissions of the arguments.source file is:

-rw-r--r--.  1 lucee webservices 2.8K Jan 30 16:41 example-file.ini

If I replace the fileCopy() with fileWrite(destination, fileRead(source)); it then creates the file with the correct permissions, so it appears there’s something amiss with the permissions when a file is copied it’s not carrying over the same file permissions.

In tracking down the Lucee source code, it looks like the file copies are done via:

Files.copy(in.toPath(), out.toPath(), StandardCopyOption.REPLACE_EXISTING)

Should it be using both REPLACE_EXISTING and COPY_ATTRIBUTES so the attributes are copied?

So I tracked down the issue between the two VMs.

On the working VM, the file being copied the group had write permissions and on the non-working VM, the group only had read permissions. The owner of the source file is different than the tomcat service, which appears to be the problem.

However, this same file structure works fine in Java 11 and Lucee 5 (although the OS is CentOS 7 versus Oracle Linux 9).

My assumption was that if the source file had write permissions for the owner, the copied file would also have write permissions for the owner but given that the tomcat service only has read access to the file, it’s why it’s copied with read (even though it’s the owner of the file).

So I guess the question is should Lucee be able to write to a file it just copied?

@Zackster / @micstriit Any thoughts?

https://luceeserver.atlassian.net/browse/LDEV-6095

I will say, I’m not 100% sure this is a bug, but if I do something like this from the CLI when the file is owned by a lucee user and both the lucee and tomcat users are in the same group, the permissions are preserved to the new file, but the owner and group of the file are now tomcat.

sudo -u tomcat cp /var/www/_tmp/testfile.txt /tmp/

So while I can see why I can certainly see an angle that Lucee is being more cautious and secure, it certainly would seem like any file created by Lucee should have write permissions unless you specifically want to remove it.