Skip to content

fix: eliminate TOCTOU race in scan-status update - #511

Open
cschuerings wants to merge 1 commit into
cap-js:mainfrom
cschuerings:fix/toctou-scan-status
Open

fix: eliminate TOCTOU race in scan-status update#511
cschuerings wants to merge 1 commit into
cap-js:mainfrom
cschuerings:fix/toctou-scan-status

Conversation

@cschuerings

Copy link
Copy Markdown
Contributor

Problem

When a file is replaced while a scan is already in flight, the scan completion WHERE clause used hash IS NULL OR hash = <old-hash> to find the row to stamp. Under concurrent uploads this is a TOCTOU race: the replacement upload starts a new scan that immediately sets hash = NULL and begins scanning the new file. The old scan's completion query then matches the now-NULL hash and stamps its verdict — which belongs to the replaced file — onto the row for the new file.

The result is that a clean new file can be marked Infected (or vice versa) purely due to ordering of DB writes.

Fix

Introduce a scanToken UUID column on the Attachment type. updateStatus generates a fresh token when transitioning to Scanning, stores it in the row, and returns it to _scanAttachmentsFile. The scan-completion WHERE clause then matches on scanToken = <token> instead of hash IS NULL. If a concurrent upload has already started a new scan (overwriting scanToken), the stale completion query matches zero rows and the wrong verdict is safely discarded.

The hash IS NULL disjunct is removed entirely from the completion path.

Out of Scope

Crash-recovery scenarios (attachment stuck in Scanning after a process crash between the Scanning and Clean writes) are a separate concern not addressed here.

@cschuerings
cschuerings marked this pull request as ready for review August 4, 2026 14:58
@cschuerings
cschuerings requested a review from a team as a code owner August 4, 2026 14:58
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.

1 participant