View Issue Details

IDProjectCategoryView StatusLast Update
0006269SOGoWeb Address Bookpublic2026-11-06 13:39
ReporterKewinDousse Assigned To 
PrioritynormalSeveritymajorReproducibilityalways
Status newResolutionopen 
PlatformDockerOSDebianOS Version13
Summary0006269: CardDAV DELETE deletes a contact despite a non-matching If-Match
Description

On SOGo 5.12.13, a DELETE request with a non-matching If-Match returns 204 No Content and deletes the contact. It should return 412 Precondition Failed and leave the contact unchanged.

This prevents clients from using If-Match to protect against deleting a contact modified by another client.

Steps To Reproduce

Use a disposable test account. Export BOOK_URL with its personal address book URL, and DAV_USER and DAV_PASSWORD with its credentials. For example, BOOK_URL may be http://localhost:8080/SOGo/dav/alice/Contacts/personal/.

Run the following in a shell script. The resource name must be unused; the script stops if creation fails.

set -eu
: "${BOOK_URL:?}" "${DAV_USER:?}" "${DAV_PASSWORD:?}"
CARD_URL="${BOOK_URL%/}/if-match-delete-probe.vcf"

printf '%s\r\n' \
  'BEGIN:VCARD' 'VERSION:3.0' \
  'UID:if-match-delete-probe' 'FN:Conditional Delete Probe' \
  'N:Probe;Conditional Delete;;;' 'END:VCARD' |
curl --silent --show-error --fail --include \
  --user "$DAV_USER:$DAV_PASSWORD" --request PUT \
  --header 'If-None-Match: *' \
  --header 'Content-Type: text/vcard; charset=utf-8' \
  --data-binary @- "$CARD_URL"

curl --silent --show-error --fail --include \
  --user "$DAV_USER:$DAV_PASSWORD" "$CARD_URL"

curl --silent --show-error --include \
  --user "$DAV_USER:$DAV_PASSWORD" --request DELETE \
  --header 'If-Match: "deliberately-stale-etag"' "$CARD_URL"

curl --silent --show-error --include \
  --user "$DAV_USER:$DAV_PASSWORD" "$CARD_URL"

Observed:

  1. PUT: 201 Created.
  2. GET: 200 OK, with ETag: "gcs00000000".
  3. DELETE with If-Match: "deliberately-stale-etag": 204 No Content.
  4. GET: 404 Not Found.

Expected: step 3 returns 412 Precondition Failed; step 4 returns 200 OK with the contact unchanged.

Additional Information

Reproduced on 6 November 2026 with SOGo 5.12.13 and SOPE 5.12.13 compiled from official release archives in a Debian 13 Docker container, with PostgreSQL, SQL authentication and Nginx. The master branch has not been tested.

Reference: RFC 9110, section 13.1.1 (If-Match):
https://www.rfc-editor.org/rfc/rfc9110.html#section-13.1.1

TagsNo tags attached.

Activities

KewinDousse

KewinDousse

2026-11-06 13:13

reporter   ~0018603

My bad, the code block in the report displays double quotes as literal " entities.

I've attached the script as a file here, with the correct quoting.

ifmatch-repro.sh (857 bytes)   
#!/bin/sh
set -eu
: "${BOOK_URL:?}" "${DAV_USER:?}" "${DAV_PASSWORD:?}"
CARD_URL="${BOOK_URL%/}/if-match-delete-probe.vcf"

printf '%s\r\n' \
  'BEGIN:VCARD' 'VERSION:3.0' \
  'UID:if-match-delete-probe' 'FN:Conditional Delete Probe' \
  'N:Probe;Conditional Delete;;;' 'END:VCARD' |
curl --silent --show-error --fail --include \
  --user "$DAV_USER:$DAV_PASSWORD" --request PUT \
  --header 'If-None-Match: *' \
  --header 'Content-Type: text/vcard; charset=utf-8' \
  --data-binary @- "$CARD_URL"

curl --silent --show-error --fail --include \
  --user "$DAV_USER:$DAV_PASSWORD" "$CARD_URL"

curl --silent --show-error --include \
  --user "$DAV_USER:$DAV_PASSWORD" --request DELETE \
  --header 'If-Match: "deliberately-stale-etag"' "$CARD_URL"

curl --silent --show-error --include \
  --user "$DAV_USER:$DAV_PASSWORD" "$CARD_URL"
ifmatch-repro.sh (857 bytes)   
KewinDousse

KewinDousse

2026-11-06 13:39

reporter   ~0018604

The previous attachment had Windows CRLF line endings. This version uses LF line endings and can be run on Linux.
Also the category of the report should have been "Backend addres book".

ifmatch-repro-2.sh (835 bytes)   
#!/bin/sh
set -eu
: "${BOOK_URL:?}" "${DAV_USER:?}" "${DAV_PASSWORD:?}"
CARD_URL="${BOOK_URL%/}/if-match-delete-probe.vcf"

printf '%s\r\n' \
  'BEGIN:VCARD' 'VERSION:3.0' \
  'UID:if-match-delete-probe' 'FN:Conditional Delete Probe' \
  'N:Probe;Conditional Delete;;;' 'END:VCARD' |
curl --silent --show-error --fail --include \
  --user "$DAV_USER:$DAV_PASSWORD" --request PUT \
  --header 'If-None-Match: *' \
  --header 'Content-Type: text/vcard; charset=utf-8' \
  --data-binary @- "$CARD_URL"

curl --silent --show-error --fail --include \
  --user "$DAV_USER:$DAV_PASSWORD" "$CARD_URL"

curl --silent --show-error --include \
  --user "$DAV_USER:$DAV_PASSWORD" --request DELETE \
  --header 'If-Match: "deliberately-stale-etag"' "$CARD_URL"

curl --silent --show-error --include \
  --user "$DAV_USER:$DAV_PASSWORD" "$CARD_URL"
ifmatch-repro-2.sh (835 bytes)   

Issue History

Date Modified Username Field Change
2026-11-06 13:08 KewinDousse New Issue
2026-11-06 13:13 KewinDousse Note Added: 0018603
2026-11-06 13:13 KewinDousse File Added: ifmatch-repro.sh
2026-11-06 13:39 KewinDousse Note Added: 0018604
2026-11-06 13:39 KewinDousse File Added: ifmatch-repro-2.sh