fix: harden input validation across all RPC endpoints (PENTEST-02)
Manual security audit of 130+ RPC endpoints. Critical fixes: - LND: validate pubkey (66-char hex), Bitcoin addresses, channel points, amount bounds, payment request format, memo length, peer address - Package: validate_app_id on start/stop/restart/bundled-app handlers, validate volume host paths (must be under /var/lib/archipelago/), validate Docker image in bundled-app-start - Container: validate_app_id on all 6 handlers, canonicalize manifest paths - Network: path traversal prevention in connection request deletion - Backup: backup ID validation in delete handler - Webhooks: URL scheme validation, SSRF prevention for private IPs - Security: validate app_id in secret rotation - Interfaces: WiFi password length/null validation, strict IP/gateway/DNS parsing for static ethernet config Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
4b5eb4ed29
commit
aa6c7c2e6a
@@ -28,6 +28,38 @@ impl RpcHandler {
|
||||
config.enabled = enabled;
|
||||
}
|
||||
if let Some(url) = params.get("url").and_then(|v| v.as_str()) {
|
||||
// Validate webhook URL scheme and reject obviously dangerous targets
|
||||
if !url.is_empty() {
|
||||
if !url.starts_with("https://") && !url.starts_with("http://") {
|
||||
anyhow::bail!("Webhook URL must use HTTP(S)");
|
||||
}
|
||||
if !self.config.dev_mode && !url.starts_with("https://") {
|
||||
anyhow::bail!("Webhook URL must use HTTPS in production");
|
||||
}
|
||||
// Extract host portion and reject private/internal addresses
|
||||
let host_part = url
|
||||
.trim_start_matches("https://")
|
||||
.trim_start_matches("http://")
|
||||
.split('/')
|
||||
.next()
|
||||
.unwrap_or("")
|
||||
.split(':')
|
||||
.next()
|
||||
.unwrap_or("");
|
||||
let is_private = host_part == "localhost"
|
||||
|| host_part == "127.0.0.1"
|
||||
|| host_part == "::1"
|
||||
|| host_part.starts_with("10.")
|
||||
|| host_part.starts_with("172.")
|
||||
|| host_part.starts_with("192.168.")
|
||||
|| host_part.starts_with("169.254.");
|
||||
if is_private && !self.config.dev_mode {
|
||||
anyhow::bail!("Webhook URL must not point to private/local addresses");
|
||||
}
|
||||
if url.len() > 2048 {
|
||||
anyhow::bail!("Webhook URL too long");
|
||||
}
|
||||
}
|
||||
config.url = url.to_string();
|
||||
}
|
||||
if let Some(secret) = params.get("secret").and_then(|v| v.as_str()) {
|
||||
|
||||
Reference in New Issue
Block a user