Vulnerability
lsp/client.rs truncates an LSP server's JSON-RPC error message field by byte length before logging and returning it, using a raw byte-index slice instead of a UTF-8-safe boundary:
let message = if error.message.len() > 200 {
format!("{}... (truncated)", &error.message[..200])
} else {
error.message.clone()
};
error.message comes directly from the spawned LSP server's JSON-RPC error response and is not validated for length in a char-boundary-safe way before slicing.
Severity
High — the workspace sets panic = "abort" (Cargo.toml:61), so any reachable panic terminates the entire mcpls process rather than just the failing task, escalating what would otherwise be a Medium/DoS-scoped finding into a full outage of every active LSP session and in-flight MCP tool call.
Location
crates/mcpls-core/src/lsp/client.rs:541-542
Attack Scenario
A malicious or compromised LSP server (or a language server responding to attacker-controlled workspace content, e.g. a crafted symbol/file name it echoes back in an error) returns a JSON-RPC error whose message field contains multi-byte UTF-8 characters positioned so that byte offset 200 falls in the middle of a character. &error.message[..200] panics with "byte index 200 is not a char boundary". Because panic = "abort" is set, this aborts the whole mcpls process, dropping every language server connection and every pending MCP tool call — a single malformed error response from one LSP server takes down the bridge for all servers and all clients.
Remediation
Truncate on a char boundary instead of a raw byte index, e.g.:
let message = if error.message.len() > 200 {
let cut = error.message
.char_indices()
.map(|(i, _)| i)
.take_while(|&i| i <= 200)
.last()
.unwrap_or(0);
format!("{}... (truncated)", &error.message[..cut])
} else {
error.message.clone()
};
Or use .chars().take(200).collect::<String>().
References
CWE-248 (Uncaught Exception), CWE-20 (Improper Input Validation)
Vulnerability
lsp/client.rstruncates an LSP server's JSON-RPC errormessagefield by byte length before logging and returning it, using a raw byte-index slice instead of a UTF-8-safe boundary:error.messagecomes directly from the spawned LSP server's JSON-RPC error response and is not validated for length in a char-boundary-safe way before slicing.Severity
High — the workspace sets
panic = "abort"(Cargo.toml:61), so any reachable panic terminates the entire mcpls process rather than just the failing task, escalating what would otherwise be a Medium/DoS-scoped finding into a full outage of every active LSP session and in-flight MCP tool call.Location
crates/mcpls-core/src/lsp/client.rs:541-542Attack Scenario
A malicious or compromised LSP server (or a language server responding to attacker-controlled workspace content, e.g. a crafted symbol/file name it echoes back in an error) returns a JSON-RPC error whose
messagefield contains multi-byte UTF-8 characters positioned so that byte offset 200 falls in the middle of a character.&error.message[..200]panics with "byte index 200 is not a char boundary". Becausepanic = "abort"is set, this aborts the whole mcpls process, dropping every language server connection and every pending MCP tool call — a single malformed error response from one LSP server takes down the bridge for all servers and all clients.Remediation
Truncate on a char boundary instead of a raw byte index, e.g.:
Or use
.chars().take(200).collect::<String>().References
CWE-248 (Uncaught Exception), CWE-20 (Improper Input Validation)