jdx/mise · critical
refusing firewall default incoming {} over SSH: blocking rul
Error message
refusing firewall default incoming {} over SSH: blocking rule '{}' precedes a proven allow for peer {} on server port {}; reorder or narrow the rule, or set allow_lockout = true What it means
Order-sensitive lockout guard for nftables and ufw: with deny-by-default incoming traffic, the first matching rule wins, and mise found a blocking (deny/reject) rule that matches the current SSH peer and server port before any unrestricted covering allow was seen (`covered` is still false). Applying this ruleset would drop the management session mid-apply, so mise refuses. Declaration order in the rules list is the rendered order for these backends.
Source
Thrown at src/system/firewall.rs:502
for rule in rules.iter().filter(|rule| {
rule.state == FirewallRuleState::Present
&& rule.direction == FirewallDirection::Incoming
&& rule
.protocol
.is_none_or(|protocol| protocol == FirewallProtocol::Tcp)
&& rule
.port
.is_none_or(|port| port.contains(connection.server_port))
&& rule
.source
.is_none_or(|source| source.contains(&connection.peer))
&& rule
.destination
.is_none_or(|destination| destination.contains(&connection.server))
}) {
if rule.action != FirewallAction::Allow {
match backend {
Some(FirewallBackend::Nftables | FirewallBackend::Ufw) if !covered => bail!(
"refusing firewall default incoming {} over SSH: blocking rule '{}' precedes a proven allow for peer {} on server port {}; reorder or narrow the rule, or set allow_lockout = true",
self.default_incoming.ufw(),
rule.name,
connection.peer,
connection.server_port
),
Some(FirewallBackend::Firewalld) => bail!(
"refusing firewall default incoming {} over SSH: blocking rule '{}' also covers peer {} on server port {}, and firewalld cannot guarantee the allow wins; narrow the rule or set allow_lockout = true",
self.default_incoming.ufw(),
rule.name,
connection.peer,
connection.server_port
),
// An automatic backend is validated again after it is
// resolved.
_ => {}
}
continue;View on GitHub (pinned to 9dcfcaa0dc)
Solutions
- Move the SSH allow rule above the broad deny in the rules array — order matters for nftables/ufw rendering.
- Narrow the blocking rule so it no longer matches the session: exclude your management IP from its source CIDR, or remove the SSH port from its port range.
- Switch the rule to a different interface or port scope that provably cannot cover peer + server port.
- With out-of-band console access, set `allow_lockout = true` to proceed despite the risk.
Example fix
# before (mise.toml) — deny precedes the allow [[bootstrap.linux.firewall.rules]] name = "block-lan" source = "10.0.0.0/8" action = "deny" [[bootstrap.linux.firewall.rules]] name = "ssh-ops" source = "10.0.0.8/32" port = 22 protocol = "tcp" action = "allow" # after — allow first, then the broad deny [[bootstrap.linux.firewall.rules]] name = "ssh-ops" source = "10.0.0.8/32" port = 22 protocol = "tcp" action = "allow" [[bootstrap.linux.firewall.rules]] name = "block-lan" source = "10.0.0.0/8" action = "deny"
Defensive patterns
Strategy: try-catch
Validate before calling
# pre-flight: an unrestricted-interface allow for the SSH port must precede any matching deny # (manual review of declaration order in mise.toml; the guard itself is the executable check)
Try / catch
if ! mise bootstrap firewall apply 2>fw.err; then
if grep -q "precedes a proven allow" fw.err; then
# reorder rules in mise.toml: management allow above broad denies, then retry
echo "reorder: put the ssh allow first in [[bootstrap.linux.firewall.rules]]"; exit 1
fi
cat fw.err; exit 1
fi Prevention
- Declare the management allow as the first rule in the file, always.
- Review `mise bootstrap firewall apply --dry-run` output ordering once validation passes.
- Prefer narrow denies over broad 0.0.0.0/0 blocks on management ports.
When it happens
Trigger: `mise bootstrap firewall apply` with deny-ish `default_incoming`, a verified `SSH_CONNECTION`, backend nftables or ufw, and a rule like `action = "deny", source = "10.0.0.0/8"` (matching the peer) declared before the allow covering that peer/port — the loop hits the non-allow rule while `covered == false` and bails.
Common situations: Broad deny rules (geo-blocks, LAN denies, port-sweep blocks) written above the management allow; converting legacy iptables dumps where denies came first; appending the SSH allow later in the file during refactoring.
Related errors
- refusing firewall default incoming {} over SSH: blocking rul
- refusing firewall default incoming {} from an SSH-derived pr
- refusing firewall default incoming {} without SSH_CONNECTION
- refusing firewall default incoming {} over SSH: no incoming
- firewall rule '{}' uses protocol {}, which UFW does not supp
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/cceb3c44e00ab8a7.
Report an issue: GitHub.