Fetch the referenced LLM with the caller session before filling access URL fields.
Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Require role_id and reuse the role add-policy checks when creating a binding.
Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Keep the caller session when authorizing assume and reuse join-project role checks.
Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
When admin or scope query parameters do not map to a concrete view, use the resource's own scope and keep owner filters applied.
Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Allow force restart when instances are failed, protect restarting status
during sync, refresh GPU memory from deployment, and tolerate crash-loop
while waiting for service ready.
Align the csrf resource handler with other API resource handlers by requiring a token and forwarding with the caller's own session.
Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
The sftp list/download/upload endpoints were not protected by
authentication, only by the UUID4 session id. Anyone who learned the
session id (it appears in URLs and logs) could list, download and
upload files of the VM over the victim's active SSH/SFTP channel.
Wrap all three endpoints with auth.Authenticate and record the owner
of each sftp session at registration, so only the user who opened the
session can use it.
Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
Co-authored-by: Claude <noreply@anthropic.com>
The ssh console endpoint accepted a raw ip address in the URL path
and dialed it directly with user provided credentials, so any
authenticated user could use the webconsole service as an internal
SSH proxy, port scanner and credential brute-forcer.
Resolve the ip against hosts (access_ip) and servers (ip_addr)
visible to the user's session and require it to match one of them,
rejecting all other addresses.
Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
Co-authored-by: Claude <noreply@anthropic.com>
- Reject signed requests older or newer than 15 minutes (x-amz-date
for v4, Date for v2), so intercepted valid requests can no longer
be replayed indefinitely
- Decode the object key exactly once: r.URL.Path is already decoded
by net/http and is the form the signature covers, decoding again
let a signature for one key be replayed against another
(e.g. %252e%252e%252f resolving to ../)
- Add unit tests for both behaviors
Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
Co-authored-by: Claude <noreply@anthropic.com>
The k8s shell/log endpoints fetched the target cluster kubeconfig
with the admin session, bypassing RBAC and owner scope checks, so any
authenticated user could exec into pods and read logs of any
registered cluster.
Fetch the kubeconfig with the user's own session instead, so policy
checks and owner filtering apply, and command records are attributed
to the real user.
Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
Co-authored-by: Claude <noreply@anthropic.com>
The AES key encrypting all console session tokens was derived from
rand.Float32 with only about 24 bits of entropy, so it could be
recovered by brute force from a single known (session id, token)
pair and then be used to forge access tokens of arbitrary sessions.
Generate the key from 32 crypto/rand bytes instead (about 192 bits
of effective entropy). Sessions live in process memory only, so a
per-process random key is sufficient.
Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
Co-authored-by: Claude <noreply@anthropic.com>
RemoteRDPConsoleInfo.GetId() always returned an empty string, so all
RDP sessions were stored under the same key in the session manager:
any valid RDP access token resolved to whatever RDP session was stored
last, letting a user take over another user's console session
(host/port/username/password).
Give every RDP session a random UUID id and validate in
SSessionManager.Get that the presented access token is exactly the
one issued for the session, so sessions can not be reached by any
other token.
Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
Co-authored-by: Claude <noreply@anthropic.com>
With cors_hosts unset (the default), the CORS middleware allowed all
origins and echoed the request origin together with
Access-Control-Allow-Credentials, so any website could make
authenticated cross-origin requests against the API with the user's
cookies.
Credentials are now only honored for explicitly listed origins:
with an empty or wildcard origin allowlist the middleware responds
with Access-Control-Allow-Origin: * and no credentials header.
Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
Co-authored-by: Claude <noreply@anthropic.com>
- Generate verification codes with crypto/rand instead of the
predictable time-seeded math/rand
- Count failed verification attempts and invalidate the code after
verify_max_attempts (default 5) failures, closing the unlimited
online brute force of the 6-digit code at the login endpoint
- Delete the verification record after a successful check so codes
are single use and can not be replayed within the validity window
- Add unit tests for code generation
Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
Co-authored-by: Claude <noreply@anthropic.com>
The nbd export endpoints interpolated the request disk_id into
shell commands (sh -c with the joined qemu-nbd command line, and
ps|grep for the process check), so a crafted disk_id could execute
arbitrary commands as root on the host image service.
- Require the disk_id to be a plain UUID in both export and close
endpoints
- Run qemu-nbd with argv instead of sh -c
- Check the export process via its pid file and kill -0 instead of
shell pipelines
- Add unit tests for the validation and the process check
Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
Co-authored-by: Claude <noreply@anthropic.com>
server-monitor sends arbitrary QMP/HMP commands (pmemsave, migrate,
etc.) to a running guest, which exceeds the semantics of monitoring.
As an MCP tool it could be triggered without human awareness through
LLM prompt injection or the tool-request endpoint.
Remove the mcp-desc registration tag from ServerMonitorOptions so
climcgen no longer registers the tool, drop its mention from the MCP
instructions, and add a regression test asserting it is not exposed.
The climc command and the permission-gated region API are unchanged.
Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
Co-authored-by: Claude <noreply@anthropic.com>
Full session tokens were written to logs in policy.go, mcclient auth,
oidc handler and the webconsole session manager; guest root passwords
were logged by the linux fsdriver and the nbdkit mount command; MCP
tool arguments and full JSON-RPC bodies (which may contain
server-reset-password passwords) were logged by the llm agent.
Truncate tokens in log messages, drop or mask password values and
log only the tool/method name for MCP calls.
Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
Co-authored-by: Claude <noreply@anthropic.com>
- Quote the heredoc delimiter when writing deploy params to the
deployer guest, so deploy content, passwords and other
user-supplied values are written literally and shell expansions
($(...), backticks, $VAR) inside them are not evaluated by the
remote shell
- Escape JSON passed via --deploy-params as a single POSIX shell
word, preventing single quotes in user data from breaking out of
the argument
- Add unit tests covering injection payloads
Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
Co-authored-by: Claude <noreply@anthropic.com>
- Run ssh via exec.Command argv instead of "bash -c" string
interpolation, so user-supplied fields can no longer escape into
local shell commands on the webconsole server
- Quote every interpolated value (env, command, args) as a POSIX
shell word, so they stay literal data on the remote shell
- Validate username charset and limit target_ip to climc pod or container
- Add unit tests covering injection payloads
Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
Co-authored-by: Claude <noreply@anthropic.com>
* feat(aiproxy): expose catalog context window on AI models
Populate known 1M+ context windows in catalog seed data and return
context_window in AI model list/detail API responses.
* feat(aiproxy): add instance test-connectivity and set-models actions
Add provider instance test-connectivity using stored ai_key secrets,
and set-models to import selected catalog models while skipping
existing model_key rows. Register corresponding climc perform commands.