Skip to content

fix: XLS BIFF8 encryption not applied due to premature password clearing#959

Open
alaahong wants to merge 4 commits into
apache:mainfrom
alaahong:fix/xls-biff8-encryption
Open

fix: XLS BIFF8 encryption not applied due to premature password clearing#959
alaahong wants to merge 4 commits into
apache:mainfrom
alaahong:fix/xls-biff8-encryption

Conversation

@alaahong

Copy link
Copy Markdown
Member

Purpose of the pull request

The refactor in 7fe23f0 added a finally block in WorkBookUtil.createWorkBook() that clears the Biff8EncryptionKey ThreadLocal immediately after setting it. However, workbook.write() (which applies BIFF8 encryption) runs later in WriteContextImpl.finish(). At that point the password is already null, so the file content is never encrypted - only a write-protection flag is set.

Below two files, XLSX can protect the content, but xls only provide write permission protection.
sample-xls-password-buggy.xls
image

sample-xlsx-password-encrypted.xlsx
image

Since code fixed, it also protect the content as below
image

What's changed?

Fix: Remove the premature clearing. The password is correctly cleared by WriteContextImpl.clearEncrypt03() after workbook.write() completes.

Tests:

  • Update WorkBookUtilTest to verify password remains set after createWorkBook()
  • Add EncryptDataTest.xlsPasswordWrite_isActuallyEncrypted to verify that reading an encrypted XLS without a password fails

Checklist

  • I have read the Contributor Guide.
  • I have written the necessary doc or comment.
  • I have added the necessary unit tests and all cases have passed.

The refactor in 7fe23f0 added a finally block in WorkBookUtil.createWorkBook()
that clears the Biff8EncryptionKey ThreadLocal immediately after setting it.
However, workbook.write() (which applies BIFF8 encryption) runs later in
WriteContextImpl.finish(). At that point the password is already null, so
the file content is never encrypted - only a write-protection flag is set.

Fix: Remove the premature clearing. The password is correctly cleared by
WriteContextImpl.clearEncrypt03() after workbook.write() completes.

Tests:
- Update WorkBookUtilTest to verify password remains set after createWorkBook()
- Add EncryptDataTest.xlsPasswordWrite_isActuallyEncrypted to verify that
  reading an encrypted XLS without a password fails
@alaahong
alaahong requested a review from Copilot July 19, 2026 02:06

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This pull request fixes BIFF8 (XLS) content encryption by ensuring the Biff8EncryptionKey ThreadLocal remains set until workbook.write() runs (later in WriteContextImpl.finish()), and adds tests to prevent regressions.

Changes:

  • Stop clearing Biff8EncryptionKey prematurely in WorkBookUtil.createWorkBook() for XLS password-protected writes.
  • Update WorkBookUtilTest to assert the BIFF8 password remains set after workbook creation.
  • Add an integration-style test to verify an XLS written with a password cannot be read without the password.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
fesod-sheet/src/main/java/org/apache/fesod/sheet/util/WorkBookUtil.java Keeps BIFF8 encryption password set during XLS write setup (so encryption can apply during workbook.write()).
fesod-sheet/src/test/java/org/apache/fesod/sheet/util/WorkBookUtilTest.java Updates unit expectation to ensure the BIFF8 password remains available after createWorkBook().
fesod-sheet/src/test/java/org/apache/fesod/sheet/readwrite/EncryptDataTest.java Adds a regression test that validates XLS content is actually encrypted (read fails without password).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread fesod-sheet/src/main/java/org/apache/fesod/sheet/util/WorkBookUtil.java Outdated
Comment thread fesod-sheet/src/test/java/org/apache/fesod/sheet/readwrite/EncryptDataTest.java Outdated
alaahong added 2 commits July 19, 2026 10:24
Merge the assertThrows lambda argument onto a single line to comply
with the project Spotless formatting rules.
- WorkBookUtil: use !StringUtils.isEmpty() instead of != null to prevent
  empty password ThreadLocal leak (clearEncrypt03 returns early for
  empty passwords)
- EncryptDataTest: use EncryptedDocumentException instead of Exception
  for more precise assertion of encryption failure
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants