snet

stalwart bug

Aug 19th, 2026
21
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.70 KB | None | 0 0
  1. **Title:** WebDAV PROPFIND `<D:href>` is not percent-encoded for FileNode objects created via JMAP, breaking WebDAV clients (spec violation of RFC 3986)
  2.  
  3. ## Summary
  4. When a file/folder (`FileNode`) is created through the **JMAP** API (`FileNode/set`), the resulting object's `<D:href>` in subsequent WebDAV `PROPFIND` responses contains the **raw, unencoded name** (including literal spaces and raw UTF-8 bytes for non-ASCII characters) instead of a properly percent-encoded path segment.
  5.  
  6. Objects created directly via **WebDAV** (`MKCOL`/`PUT`) are, by contrast, always correctly percent-encoded in their `href`.
  7.  
  8. This produces a `PROPFIND` response containing an invalid URI (per RFC 3986, spaces and non-ASCII bytes in a URI path must be percent-encoded), which appears to cause spec-compliant WebDAV clients to silently fail to display or access the affected resource.
  9.  
  10. ## Reproduction steps
  11. 1. Authenticate to a Stalwart account with JMAP access
  12. 2. Create a folder via JMAP `FileNode/set`, e.g.:
  13. ```json
  14. {
  15. "using": [
  16. "urn:ietf:params:jmap:core",
  17. "urn:ietf:params:jmap:filenode",
  18. "urn:ietf:params:jmap:principals:owner"
  19. ],
  20. "methodCalls": [[
  21. "FileNode/set",
  22. {
  23. "accountId": "f",
  24. "create": { "dir0": { "name": "builtin fest folder" } }
  25. },
  26. "fns0"
  27. ]]
  28. }
  29. ```
  30. 3. Server responds with success and a real object id:
  31. ```json
  32. {
  33. "methodResponses": [[
  34. "FileNode/set",
  35. {
  36. "accountId": "f",
  37. "oldState": "s0ewq",
  38. "newState": "s0iwq",
  39. "created": { "dir0": { "id": "b7z" } }
  40. },
  41. "fns0"
  42. ]]
  43. }
  44. ```
  45. 4. Immediately after, query the same account's file storage via WebDAV:
  46. ```bash
  47. curl -u "[email protected]:password" -X PROPFIND \
  48. "https://mail.example.com/dav/file/[email protected]/" \
  49. -H "Depth: 1"
  50. ```
  51. 5. The response includes the newly created folder with an **unencoded space** in the href:
  52. ```xml
  53. <D:href>/dav/file/user%40domain.com/builtin fest folder/</D:href>
  54. ```
  55. Note the account name itself is correctly encoded (`%40` for `@`), but the folder name segment is not (`builtin fest folder` should be `builtin%20fest%20folder`).
  56.  
  57. ## Second reproduction (non-ASCII characters)
  58. The same behavior was independently reproduced with a folder created with an Arabic name via the same JMAP flow:
  59. ```xml
  60. <D:href>/dav/file/user%40domain.com/فثسف يسنتا سنتاي/</D:href>
  61. ```
  62. Here, the raw UTF-8 bytes are embedded directly in the href rather than being percent-encoded (expected: `%D9%81%D8%AB%D8%B3%D9%81...` etc., consistent with how every WebDAV-created resource with non-ASCII characters is correctly encoded elsewhere in the same account).
  63.  
  64. ## Control: WebDAV-created objects in the same account are correctly encoded
  65. For comparison, a folder created via a standard WebDAV `MKCOL` request in the same account:
  66. ```bash
  67. curl -u "[email protected]:password" -X MKCOL \
  68. "https://mail.example.com/dav/file/[email protected]/test-folder-curl/"
  69. ```
  70. returns a properly encoded href on subsequent PROPFIND:
  71. ```xml
  72. <D:href>/dav/file/user%40domain.com/test-folder-curl/</D:href>
  73. ```
  74. And every one of ~1,800 files/folders migrated into this same account via a third-party WebDAV client (rclone) — including many with spaces and Arabic names — are all correctly percent-encoded, e.g.:
  75. ```xml
  76. <D:href>/dav/file/user%40domain.com/eSpare%20Catalog/</D:href>
  77. <D:href>/dav/file/user%40domain.com/%D8%AC%D8%AF%D9%88%D9%84%20%D9%85%D8%AA%D8%A7%D8%A8%D8%B9%D8%A9%20%D8%B9%D9%85%D9%84%D8%A7%D8%A1.xlsx</D:href>
  78. ```
  79. This confirms the encoding logic differs specifically based on the **creation path** (JMAP vs. WebDAV), not on the presence of special characters generally.
  80.  
  81. ## Downstream impact observed
  82. 1. **`Depth: infinity` PROPFIND traversal appears to break** at or around the malformed href — a recursive listing that should include the JMAP-created folder does not surface it, while a `Depth: 1` listing on the immediate parent does include it (with the malformed href).
  83. 2. **WinSCP** (tested as a standards-compliant WebDAV client control) does not display the JMAP-created folder in its listing at all, while it correctly displays every WebDAV-created resource in the same directory, including ones with spaces and Arabic names.
  84. 3. This is suspected to be the underlying cause of a related issue observed in a JMAP-based webmail client (Bulwark Webmail): objects created via JMAP `FileNode/set` return a successful response with a real object id and an advanced `state`, but the client's subsequent listing/refresh (which appears to rely on WebDAV `PROPFIND`, or shares the same href-serialization code path) never displays the newly created object, even after manual refresh, navigation, or a full page reload.
  85.  
  86. ## Suggested fix
  87. When serializing a `FileNode`'s path into a WebDAV `<D:href>`, the server should percent-encode each path segment consistently, regardless of whether the underlying object was created via the JMAP or WebDAV API. The encoding logic used for WebDAV-created resources (which is correct) should be applied uniformly to all resources when generating `PROPFIND`/other WebDAV responses.
  88.  
  89. ## Environment
  90. - Stalwart Mail Server version: **v0.16.18** (also reproduced on v0.16.11 prior to upgrading, ruling out a version-specific regression)
  91. - Deployment: Docker (`stalwartlabs/stalwart:v0.16`)
  92. - Storage backend: default (RocksDB)
  93. - File access path tested: `/dav/file/{account}`
  94. - Client used for JMAP creation: Bulwark Webmail v1.8.1 (browser DevTools Network tab used to capture the exact JMAP request/response shown above)
  95. - Client used for WebDAV verification: `curl` (raw PROPFIND) and WinSCP (independent GUI WebDAV client)
Tags: Bugs
Advertisement
Add Comment
Please, Sign In to add comment