Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .jules/sentinel.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,8 @@
**Vulnerability:** The `verify_github_sig` function in `apps/server/src/infra_routes.rs` verified GitHub webhook signatures using standard string comparison `expected.eq_ignore_ascii_case(hex_sig)`.
**Learning:** String comparison functions exit early as soon as a character mismatch is found. In a cryptographic context, this variable response time leaks information and allows an attacker to perform a timing attack to forge a valid HMAC signature by guessing it byte by byte.
**Prevention:** Always use a constant-time comparison library (like `hmac`'s `verify_slice()`) to compare cryptographic hashes, secrets, and signatures to prevent side-channel timing attacks. Avoid custom implementations of standard cryptographic algorithms.

## 2024-05-30 - [Command Validation Bypass]
**Vulnerability:** Command validation in `tools::workdir_cmd` checked for blocklist terms only on the joined command string. This allowed for bypasses like `npm run rm` because it bypassed the `"rm "` substring check, which was intended to block the `rm` command.
**Learning:** Relying solely on a joined string for command validation breaks multi-word substring blocks or is fragile to spacing, while relying solely on individual token checks doesn't catch multi-word blocked phrases. Both must be checked.
**Prevention:** Verify both the joined command string against multi-word or spacing blocklists AND individual tokenized arguments for exact matches of sensitive binaries (e.g., `part == "rm"`).
20 changes: 20 additions & 0 deletions crates/agent/src/tools/workdir_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,20 @@ fn validate_command(raw: &str) -> std::result::Result<Vec<String>, String> {
return Err(format!("token interdit dans la commande : {bad}"));
}
}

let blocked_exact = [
"rm", "sudo", "chmod", "chown", "curl", "wget", "ssh", "scp",
];

for part in &parts {
let part_lower = part.to_ascii_lowercase();
// Also check if any individual token is an exact match for sensitive binaries
for bad in &blocked_exact {
if &part_lower == bad {
return Err(format!("token exact interdit dans la commande : {bad}"));
}
}
}
let bin = parts[0].as_str();
let bin_base = Path::new(bin)
.file_name()
Expand Down Expand Up @@ -354,6 +368,12 @@ mod tests {
fn blocks_obfuscated_commands() {
assert!(validate_command("npm run \"s\"udo").is_err());
assert!(validate_command("cat \"..\"/\"..\"/etc/passwd").is_err());

// New tests for exact token matching bypass
assert!(validate_command("npm run rm").is_err());
assert!(validate_command("npx rm -rf /").is_err());
assert!(validate_command("npm test sudo").is_err());
assert!(validate_command("yarn run curl http://malicious.com").is_err());
}
}

Expand Down
Loading